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

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

#include <config.h>

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

#include "internal.h"
#include "datatypes.h"
#include "domain_conf.h"
45
#include "snapshot_conf.h"
46
#include "network_conf.h"
47
#include "virerror.h"
48
#include "domain_event.h"
49
#include "storage_conf.h"
50
#include "virstoragefile.h"
51
#include "viruuid.h"
52
#include "viralloc.h"
53
#include "nodeinfo.h"
54
#include "virlog.h"
55
#include "vbox_driver.h"
56
#include "configmake.h"
E
Eric Blake 已提交
57
#include "virfile.h"
58
#include "fdstream.h"
M
Martin Kletzander 已提交
59
#include "viruri.h"
60
#include "virstring.h"
61 62 63 64

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

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


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

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

113 114
#define VBOX_ADDREF(arg) (arg)->vtbl->nsisupports.AddRef((nsISupports *)(arg))

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

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

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

#if VBOX_API_VERSION < 3001

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

#else  /* VBOX_API_VERSION >= 3001 */

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

#endif /* VBOX_API_VERSION >= 3001 */
166

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

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

194 195
typedef struct {
    virMutex lock;
196
    unsigned long version;
197 198

    virCapsPtr caps;
199
    virDomainXMLOptionPtr xmlopt;
200 201 202

    IVirtualBox *vboxObj;
    ISession *vboxSession;
203 204 205

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

#if VBOX_API_VERSION == 2002

} vboxGlobalData;

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

213 214
    /* Async event handling */
    virDomainEventStatePtr domainEvents;
215 216
    int fdWatch;

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

    nsIEventQueue  *vboxQueue;
    int volatile vboxCallBackRefCount;

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

228 229
} vboxGlobalData;

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

240
static vboxGlobalData *g_pVBoxGlobalData = NULL;
241 242

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

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

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

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

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

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

#else /* VBOX_API_VERSION >= 4000 */

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

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

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

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

#endif /* VBOX_API_VERSION >= 4000 */

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

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

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

#if VBOX_API_VERSION == 2002
287

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

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

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

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

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

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

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

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

368
# ifdef WIN32
369

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

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

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

399
    nsIDFromChar((nsID *)&iid->value, uuid);
400 401
}

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

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

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

#  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) {
448 449 450
        return;
    }

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

472
    sa_assert(iid->value);
473
    nsIDFromChar(iid->value, uuid);
474 475
}

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

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

    iid->value = &iid->backing;

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

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

503
#else /* VBOX_API_VERSION != 2002 */
504

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

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

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

537
    ignore_value(virUUIDParse(utf8, uuid));
538 539

    data->pFuncs->pfnUtf8Free(utf8);
540 541
}

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

548
    vboxIIDUnalloc_v3_x(data, iid);
549

550
    virUUIDFormat(uuid, utf8);
551

552 553
    data->pFuncs->pfnUtf8ToUtf16(utf8, &iid->value);
}
554

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

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

570 571
    return memcmp(uuid1, uuid2, VIR_UUID_BUFLEN) == 0;
}
572 573


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

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

584 585 586 587 588 589 590 591

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

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

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

622 623
    if (!aMaxPortPerInst ||
        !aMaxSlotPerPort)
624 625
        return NULL;

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

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

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

645
    name = virIndexToDiskName(total, prefix);
646

647
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
648
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
649
          NULLSTR(name), total, storageBus, deviceInst, devicePort,
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
          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;

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

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

    total = virDiskNameToIndex(deviceName);

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

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

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

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

    return true;
}

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

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

    if (!vbox)
        return false;

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

    if (!sysProps)
        return false;

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

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

    VBOX_RELEASE(sysProps);

    return true;
}

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

    if (!strUtf16)
        return -1;

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

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

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

806
# endif /* VBOX_API_VERSION >= 3001 */
807

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

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

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

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

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

    result = 0;

cleanup:
    VBOX_UTF8_FREE(utf8);

    return result;
}

849

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


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


863 864
static virCapsPtr vboxCapsInit(void)
{
865 866 867
    virCapsPtr caps;
    virCapsGuestPtr guest;

868
    if ((caps = virCapabilitiesNew(virArchFromHost(),
869 870 871
                                   0, 0)) == NULL)
        goto no_memory;

872
    if (nodeCapsInitNUMA(caps) < 0)
873 874 875 876
        goto no_memory;

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

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

892 893 894
    return caps;

no_memory:
895
    virObjectUnref(caps);
896 897 898
    return NULL;
}

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

    if (data->pFuncs == NULL)
905
        goto cleanup;
906 907 908

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

913
# if VBOX_API_VERSION == 2002
914 915 916

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

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

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

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

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

930
# endif /* !(VBOX_API_VERSION == 2002) */
931
#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
932 933

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

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

    return 0;

cleanup:
    return -1;
}

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

963
        VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion);
964

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

968 969
        VBOX_UTF8_FREE(vboxVersion);
        VBOX_COM_UNALLOC_MEM(versionUtf16);
970 971 972
    }

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

976 977 978 979
    return ret;
}

static void vboxUninitialize(vboxGlobalData *data) {
980 981 982
    if (!data)
        return;

983 984
    if (data->pFuncs)
        data->pFuncs->pfnComUninitialize();
985

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

996

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

E
Eric Blake 已提交
1004 1005
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

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

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

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

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

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

1039
    if (VIR_ALLOC(data) < 0)
1040
        return VIR_DRV_OPEN_ERROR;
1041

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

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

    /* No domainEventCallbacks in 2.2.* version */

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

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

    data->conn = conn;
    g_pVBoxGlobalData = data;

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

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

    return VIR_DRV_OPEN_SUCCESS;
}

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

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

    return 0;
}

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

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

    return 0;
}

1093 1094 1095 1096 1097 1098 1099

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


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

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

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

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

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

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

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}


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

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

    return ret;
}

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

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

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

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

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

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

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

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

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

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

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

1230 1231 1232 1233 1234
    virDomainPtr dom;

    virCheckFlags(0, NULL);

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

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

    return dom;
}

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

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

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

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

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

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

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

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

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

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

1309
    vboxArrayRelease(&machines);
1310 1311

    return ret;
1312 1313 1314
}

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

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

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

1336 1337
        if (!machine)
            continue;
1338

1339 1340
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1341

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

1348
            if (memcmp(uuid, iid_as_uuid, VIR_UUID_BUFLEN) == 0) {
1349

1350
                PRUint32 state;
1351

1352
                matched = 1;
1353

1354 1355
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1356

1357
                machine->vtbl->GetState(machine, &state);
1358

1359 1360 1361 1362 1363
                /* 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.
                 */
1364

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

1372 1373
            if (matched == 1)
                break;
1374 1375 1376
        }
    }

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

    return ret;
1383 1384 1385
}

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

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

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

1407 1408
        if (!machine)
            continue;
1409

1410 1411
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1412

1413 1414
            machine->vtbl->GetName(machine, &machineNameUtf16);
            VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1415

1416
            if (STREQ(name, machineNameUtf8)) {
1417

1418
                PRUint32 state;
1419

1420
                matched = 1;
1421

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

1426
                machine->vtbl->GetState(machine, &state);
1427

1428 1429 1430 1431 1432
                /* 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.
                 */
1433

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

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

1448
    vboxArrayRelease(&machines);
1449 1450

    return ret;
1451 1452
}

1453 1454

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

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

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

        if (!machine)
            continue;

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

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

1488
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
1489

1490
                PRUint32 state;
1491

1492
                matched = 1;
1493

1494 1495
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1496

1497
                machine->vtbl->GetState(machine, &state);
1498

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

1506 1507
            if (matched == 1)
                break;
1508 1509 1510
        }
    }

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

1516 1517 1518 1519
    return ret;
}


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

    ret = 1;

cleanup:
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1543 1544 1545
}


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

    ret = 0;

cleanup:
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1568 1569
}

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

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

1587 1588
    if (!machine)
        goto cleanup;
1589

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

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

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

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

1629
    PRBool isAccessible = PR_FALSE;
1630

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

1639 1640
    if (!machine)
        goto cleanup;
1641

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

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

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

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

1683 1684
    virCheckFlags(0, -1);

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

1693 1694
    if (!machine)
        goto cleanup;
1695

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

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

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

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

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


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

E
Eric Blake 已提交
1741 1742
    virCheckFlags(0, -1);

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

1751 1752
    if (!machine)
        goto cleanup;
1753

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

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

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

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

1792 1793
    virCheckFlags(0, -1);

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

1802 1803
    if (!machine)
        goto cleanup;
1804

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

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

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

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

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

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

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

1856
    ignore_value(VIR_STRDUP(osType, "hvm"));
1857
    return osType;
1858 1859 1860
}

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

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

1876 1877
    if (!machine)
        goto cleanup;
1878

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

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

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

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

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

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

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

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

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

1957 1958
        if (!machine)
            continue;
1959

1960 1961
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1962

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


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

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

1999
                ret = 0;
2000 2001
            }

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

    }

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

cleanup:
    return ret;
}

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

    virCheckFlags(0, -1);

    vboxIIDFromUUID(&domiid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
    if (NS_FAILED(rc)) {
2033 2034
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
2035 2036 2037 2038 2039
        goto cleanup;
    }

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

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

    if (reason)
        *reason = 0;

    ret = 0;

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

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

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

2066
    /* Open a Session for the machine */
2067
    vboxIIDFromUUID(&iid, dom->uuid);
2068 2069 2070 2071
#if VBOX_API_VERSION >= 4000
    /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
2072 2073
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
2074 2075 2076 2077 2078
        return -1;
    }
#endif

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

2084
            console->vtbl->SaveState(console, &progress);
2085

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

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

2105
    DEBUGIID("UUID of machine being saved:", iid.value);
2106

2107
    VBOX_RELEASE(machine);
2108
    vboxIIDUnalloc(&iid);
2109 2110 2111
    return ret;
}

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

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

2127
    vboxIIDFromUUID(&iid, dom->uuid);
2128 2129 2130 2131
#if VBOX_API_VERSION >= 4000
    /* Get machine for the call to VBOX_SESSION_OPEN */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
2132 2133
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
2134 2135 2136 2137 2138
        return -1;
    }
#endif

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

2163
    vboxIIDUnalloc(&iid);
2164 2165 2166
    return ret;
}

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

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

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

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

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

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}

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

2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304
static void vboxHostDeviceGetXMLDesc(vboxGlobalData *data, virDomainDefPtr def, IMachine *machine)
{
    IUSBController *USBController = NULL;
    PRBool enabled = PR_FALSE;
    vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER;
    size_t i;
    PRUint32 USBFilterCount = 0;

    def->nhostdevs = 0;
    machine->vtbl->GetUSBController(machine, &USBController);

    if (!USBController)
        return;

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

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

    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;

    for (i = 0; (USBFilterCount < def->nhostdevs) || (i < deviceFilters.count); i++) {
        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] = virDomainHostdevDefAlloc();
        if (!def->hostdevs[USBFilterCount])
            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);
release_controller:
    VBOX_RELEASE(USBController);
}

2305
static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
2306
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
2307 2308
    virDomainDefPtr def  = NULL;
    IMachine *machine    = NULL;
2309
    vboxIID iid = VBOX_IID_INITIALIZER;
2310
    int gotAllABoutDef   = -1;
2311
    nsresult rc;
2312

2313 2314
    /* Flags checked by virDomainDefFormat */

2315
    if (VIR_ALLOC(def) < 0)
2316 2317
        goto cleanup;

2318
    vboxIIDFromUUID(&iid, dom->uuid);
2319
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
2320
    if (NS_SUCCEEDED(rc)) {
2321
        PRBool accessible = PR_FALSE;
2322

2323 2324
        machine->vtbl->GetAccessible(machine, &accessible);
        if (accessible) {
2325
            size_t i = 0;
2326 2327 2328
            PRBool PAEEnabled                   = PR_FALSE;
            PRBool ACPIEnabled                  = PR_FALSE;
            PRBool IOAPICEnabled                = PR_FALSE;
2329
            PRBool VRDxEnabled                  = PR_FALSE;
2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350
            PRUint32 CPUCount                   = 0;
            PRUint32 memorySize                 = 0;
            PRUint32 netAdpCnt                  = 0;
            PRUint32 netAdpIncCnt               = 0;
            PRUint32 maxMemorySize              = 4 * 1024;
            PRUint32 maxBootPosition            = 0;
            PRUint32 serialPortCount            = 0;
            PRUint32 serialPortIncCount         = 0;
            PRUint32 parallelPortCount          = 0;
            PRUint32 parallelPortIncCount       = 0;
            IBIOSSettings *bios                 = NULL;
#if VBOX_API_VERSION < 3001
            PRInt32       hddNum                = 0;
            IDVDDrive    *dvdDrive              = NULL;
            IHardDisk    *hardDiskPM            = NULL;
            IHardDisk    *hardDiskPS            = NULL;
            IHardDisk    *hardDiskSS            = NULL;
            const char   *hddBus                = "IDE";
            PRUnichar    *hddBusUtf16           = NULL;
            IFloppyDrive *floppyDrive           = NULL;
#else  /* VBOX_API_VERSION >= 3001 */
2351
            vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
2352
#endif /* VBOX_API_VERSION >= 3001 */
2353 2354 2355 2356 2357
#if VBOX_API_VERSION < 4000
            IVRDPServer *VRDxServer             = NULL;
#else  /* VBOX_API_VERSION >= 4000 */
            IVRDEServer *VRDxServer             = NULL;
#endif /* VBOX_API_VERSION >= 4000 */
2358
            IAudioAdapter *audioAdapter         = NULL;
2359 2360 2361
#if VBOX_API_VERSION >= 4001
            PRUint32 chipsetType                = ChipsetType_Null;
#endif /* VBOX_API_VERSION >= 4001 */
2362
            ISystemProperties *systemProperties = NULL;
2363 2364


2365 2366 2367
            def->virtType = VIR_DOMAIN_VIRT_VBOX;
            def->id = dom->id;
            memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
2368 2369
            if (VIR_STRDUP(def->name, dom->name) < 0)
                goto cleanup;
2370

2371
            machine->vtbl->GetMemorySize(machine, &memorySize);
2372
            def->mem.cur_balloon = memorySize * 1024;
2373

2374 2375 2376 2377
#if VBOX_API_VERSION >= 4001
            machine->vtbl->GetChipsetType(machine, &chipsetType);
#endif /* VBOX_API_VERSION >= 4001 */

2378 2379 2380 2381
            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
2382
#if VBOX_API_VERSION < 4001
2383
                systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
2384 2385 2386
#else  /* VBOX_API_VERSION >= 4000 */
                systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType, &netAdpCnt);
#endif /* VBOX_API_VERSION >= 4000 */
2387 2388 2389 2390 2391 2392 2393 2394 2395
                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
             */
2396 2397
            /* def->mem.max_balloon = maxMemorySize * 1024; */
            def->mem.max_balloon = memorySize * 1024;
2398 2399

            machine->vtbl->GetCPUCount(machine, &CPUCount);
E
Eric Blake 已提交
2400
            def->maxvcpus = def->vcpus = CPUCount;
2401 2402 2403

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

2404 2405
            if (VIR_STRDUP(def->os.type, "hvm") < 0)
                goto cleanup;
2406

2407
            def->os.arch = virArchFromHost();
2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430

            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 已提交
2431
                    /* Can VirtualBox really boot from a shared folder? */
2432
                }
2433
            }
2434

2435 2436
#if VBOX_API_VERSION < 3001
            machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
2437
#elif VBOX_API_VERSION == 3001
2438
            machine->vtbl->GetCpuProperty(machine, CpuPropertyType_PAE, &PAEEnabled);
2439 2440 2441
#elif VBOX_API_VERSION >= 3002
            machine->vtbl->GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled);
#endif
2442 2443
            if (PAEEnabled)
                def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_DOMAIN_FEATURE_STATE_ON;
2444

2445 2446 2447
            machine->vtbl->GetBIOSSettings(machine, &bios);
            if (bios) {
                bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
2448 2449
                if (ACPIEnabled)
                    def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_DOMAIN_FEATURE_STATE_ON;
2450

2451
                bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
2452 2453
                if (IOAPICEnabled)
                    def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_DOMAIN_FEATURE_STATE_ON;
2454

2455 2456 2457 2458 2459
                VBOX_RELEASE(bios);
            }

            /* Currently VirtualBox always uses locatime
             * so locatime is always true here */
2460
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
2461 2462 2463 2464 2465 2466 2467 2468

            /* 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 */
2469
                        PRUint32 VRAMSize          = 8;
2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481
                        PRUint32 monitorCount      = 1;
                        PRBool accelerate3DEnabled = PR_FALSE;
                        PRBool accelerate2DEnabled = PR_FALSE;

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

                        def->videos[0]->type            = VIR_DOMAIN_VIDEO_TYPE_VBOX;
2482
                        def->videos[0]->vram            = VRAMSize * 1024;
2483 2484 2485 2486
                        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;
2487 2488 2489
                        }
                    }
                }
2490
            }
2491

2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502
            /* 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;
2503

2504
                def->ngraphics = 0;
2505

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

2510 2511 2512
                if (valueTypeUtf16) {
                    VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
                    VBOX_UTF16_FREE(valueTypeUtf16);
2513

2514
                    if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
2515 2516 2517
                        PRUnichar *keyDislpayUtf16   = NULL;
                        PRUnichar *valueDisplayUtf16 = NULL;
                        char      *valueDisplayUtf8  = NULL;
2518

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

2523 2524 2525
                        if (valueDisplayUtf16) {
                            VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
                            VBOX_UTF16_FREE(valueDisplayUtf16);
2526

J
John Ferlan 已提交
2527
                            if (strlen(valueDisplayUtf8) <= 0)
2528
                                VBOX_UTF8_FREE(valueDisplayUtf8);
2529
                        }
2530

2531 2532
                        if (STREQ(valueTypeUtf8, "sdl")) {
                            sdlPresent = 1;
2533
                            if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
2534 2535 2536 2537 2538 2539
                                /* 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++;
2540
                        }
2541

2542 2543
                        if (STREQ(valueTypeUtf8, "gui")) {
                            guiPresent = 1;
2544
                            if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
2545
                                /* just don't go to cleanup yet as it is ok to have
2546 2547
                                 * guiDisplay as NULL and we check it below if it
                                 * exist and then only use it there
2548
                                 */
2549
                            }
2550 2551
                            totalPresent++;
                        }
J
John Ferlan 已提交
2552
                        VBOX_UTF8_FREE(valueDisplayUtf8);
2553 2554
                    }

2555 2556
                    if (STREQ(valueTypeUtf8, "vrdp"))
                        vrdpPresent = 1;
2557

2558 2559
                    VBOX_UTF8_FREE(valueTypeUtf8);
                }
2560

2561 2562 2563 2564 2565 2566 2567
                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++;
                    }
2568

2569 2570 2571 2572 2573 2574 2575 2576
                    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) {
2577
                        const char *tmp;
2578
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
2579
                        tmp = virGetEnvBlockSUID("DISPLAY");
2580 2581 2582 2583
                        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
                             */
2584 2585 2586 2587 2588
                        }
                        totalPresent++;
                        def->ngraphics++;
                    }
                }
2589

2590 2591 2592 2593 2594 2595 2596 2597
#if VBOX_API_VERSION < 4000
                machine->vtbl->GetVRDPServer(machine, &VRDxServer);
#else  /* VBOX_API_VERSION >= 4000 */
                machine->vtbl->GetVRDEServer(machine, &VRDxServer);
#endif /* VBOX_API_VERSION >= 4000 */
                if (VRDxServer) {
                    VRDxServer->vtbl->GetEnabled(VRDxServer, &VRDxEnabled);
                    if (VRDxEnabled) {
2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608

                        totalPresent++;

                        if ((VIR_REALLOC_N(def->graphics, totalPresent) >= 0) &&
                            (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                            PRUnichar *netAddressUtf16   = NULL;
                            char      *netAddressUtf8    = NULL;
                            PRBool allowMultiConnection  = PR_FALSE;
                            PRBool reuseSingleConnection = PR_FALSE;
#if VBOX_API_VERSION < 3001
                            PRUint32 VRDPport = 0;
2609
                            VRDxServer->vtbl->GetPort(VRDxServer, &VRDPport);
2610 2611
                            if (VRDPport) {
                                def->graphics[def->ngraphics]->data.rdp.port = VRDPport;
2612
#elif VBOX_API_VERSION < 4000 /* 3001 <= VBOX_API_VERSION < 4000 */
2613
                            PRUnichar *VRDPport = NULL;
2614
                            VRDxServer->vtbl->GetPorts(VRDxServer, &VRDPport);
2615 2616 2617 2618
                            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);
2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629
#else /* VBOX_API_VERSION >= 4000 */
                            PRUnichar *VRDEPortsKey = NULL;
                            PRUnichar *VRDEPortsValue = NULL;
                            VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey);
                            VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDEPortsKey, &VRDEPortsValue);
                            VBOX_UTF16_FREE(VRDEPortsKey);
                            if (VRDEPortsValue) {
                                /* even if vbox supports mutilpe ports, single port for now here */
                                def->graphics[def->ngraphics]->data.rdp.port = PRUnicharToInt(VRDEPortsValue);
                                VBOX_UTF16_FREE(VRDEPortsValue);
#endif /* VBOX_API_VERSION >= 4000 */
2630
                            } else {
2631
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
2632
                            }
2633

2634
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
2635

2636 2637 2638 2639 2640 2641 2642 2643
#if VBOX_API_VERSION >= 4000
                            PRUnichar *VRDENetAddressKey = NULL;
                            VBOX_UTF8_TO_UTF16("TCP/Address", &VRDENetAddressKey);
                            VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDENetAddressKey, &netAddressUtf16);
                            VBOX_UTF16_FREE(VRDENetAddressKey);
#else /* VBOX_API_VERSION < 4000 */
                            VRDxServer->vtbl->GetNetAddress(VRDxServer, &netAddressUtf16);
#endif /* VBOX_API_VERSION < 4000 */
2644 2645 2646
                            if (netAddressUtf16) {
                                VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8);
                                if (STRNEQ(netAddressUtf8, ""))
2647 2648
                                    virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0,
                                                                      netAddressUtf8, -1, true);
2649 2650 2651
                                VBOX_UTF16_FREE(netAddressUtf16);
                                VBOX_UTF8_FREE(netAddressUtf8);
                            }
2652

2653
                            VRDxServer->vtbl->GetAllowMultiConnection(VRDxServer, &allowMultiConnection);
2654
                            if (allowMultiConnection) {
2655
                                def->graphics[def->ngraphics]->data.rdp.multiUser = true;
2656
                            }
2657

2658
                            VRDxServer->vtbl->GetReuseSingleConnection(VRDxServer, &reuseSingleConnection);
2659
                            if (reuseSingleConnection) {
2660
                                def->graphics[def->ngraphics]->data.rdp.replaceUser = true;
2661
                            }
2662

2663
                            def->ngraphics++;
2664
                        } else
2665
                            virReportOOMError();
2666
                    }
2667
                    VBOX_RELEASE(VRDxServer);
2668
                }
2669
            }
2670

2671 2672 2673
#if VBOX_API_VERSION < 3001
            /* dump IDE hdds if present */
            VBOX_UTF8_TO_UTF16(hddBus, &hddBusUtf16);
2674

2675 2676 2677 2678
            def->ndisks = 0;
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0,  &hardDiskPM);
            if (hardDiskPM)
                def->ndisks++;
2679

2680 2681 2682
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1,  &hardDiskPS);
            if (hardDiskPS)
                def->ndisks++;
2683

2684 2685 2686
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1,  &hardDiskSS);
            if (hardDiskSS)
                def->ndisks++;
2687

2688 2689 2690 2691 2692 2693 2694 2695
            VBOX_UTF16_FREE(hddBusUtf16);

            if ((def->ndisks > 0) && (VIR_ALLOC_N(def->disks, def->ndisks) >= 0)) {
                for (i = 0; i < def->ndisks; i++) {
                    if (VIR_ALLOC(def->disks[i]) >= 0) {
                        def->disks[i]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
                        def->disks[i]->bus = VIR_DOMAIN_DISK_BUS_IDE;
                        def->disks[i]->type = VIR_DOMAIN_DISK_TYPE_FILE;
2696
                    }
2697
                }
2698
            }
2699

2700 2701 2702 2703
            if (hardDiskPM) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2704

2705 2706
                hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2707

2708
                hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);
2709

2710
                if (hddType == HardDiskType_Immutable)
2711
                    def->disks[hddNum]->readonly = true;
2712 2713
                ignore_value(VIR_STRDUP(def->disks[hddNum]->src, hddlocation));
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hda"));
2714
                hddNum++;
2715

2716 2717 2718 2719
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPM);
            }
2720

2721 2722 2723 2724
            if (hardDiskPS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2725

2726 2727
                hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2728

2729
                hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);
2730

2731
                if (hddType == HardDiskType_Immutable)
2732
                    def->disks[hddNum]->readonly = true;
2733 2734
                ignore_value(VIR_STRDUP(def->disks[hddNum]->src, hddlocation));
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdb"));
2735
                hddNum++;
2736

2737 2738 2739 2740
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPS);
            }
2741

2742 2743 2744 2745
            if (hardDiskSS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2746

2747 2748
                hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2749

2750
                hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);
2751

2752
                if (hddType == HardDiskType_Immutable)
2753
                    def->disks[hddNum]->readonly = true;
J
Ján Tomko 已提交
2754 2755 2756
                ignore_value(VIR_STRDUP(def->disks[hddNum]->src, hddlocation));
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdd"));
                hddNum++;
2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769

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

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

            /* get the number of attachments */
2773 2774
            for (i = 0; i < mediumAttachments.count; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2775 2776 2777 2778 2779 2780 2781
                if (imediumattach) {
                    IMedium *medium = NULL;

                    imediumattach->vtbl->GetMedium(imediumattach, &medium);
                    if (medium) {
                        def->ndisks++;
                        VBOX_RELEASE(medium);
2782 2783
                    }
                }
2784
            }
2785

2786 2787 2788 2789 2790 2791
            /* 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;
2792 2793
                    }
                }
2794 2795 2796 2797 2798 2799 2800 2801
            } else {
                error = true;
            }

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

            /* get the attachment details here */
2802 2803
            for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836
                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;
                }
2837

2838 2839 2840
                medium->vtbl->GetLocation(medium, &mediumLocUtf16);
                VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
                VBOX_UTF16_FREE(mediumLocUtf16);
2841
                ignore_value(VIR_STRDUP(def->disks[diskCount]->src, mediumLocUtf8));
2842 2843 2844 2845 2846 2847 2848 2849
                VBOX_UTF8_FREE(mediumLocUtf8);

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

2851 2852 2853 2854 2855 2856 2857 2858 2859 2860
                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;
                }
2861

2862 2863 2864 2865 2866 2867 2868 2869 2870 2871
                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);
2872
                def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
2873 2874 2875 2876 2877 2878
                                                                    deviceInst,
                                                                    devicePort,
                                                                    deviceSlot,
                                                                    maxPortPerInst,
                                                                    maxSlotPerPort);
                if (!def->disks[diskCount]->dst) {
2879 2880 2881 2882
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Could not generate medium name for the disk "
                                     "at: controller instance:%u, port:%d, slot:%d"),
                                   deviceInst, devicePort, deviceSlot);
2883 2884 2885 2886 2887
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2888

2889 2890
                medium->vtbl->GetReadOnly(medium, &readOnly);
                if (readOnly == PR_TRUE)
2891
                    def->disks[diskCount]->readonly = true;
2892

2893
                def->disks[diskCount]->type = VIR_DOMAIN_DISK_TYPE_FILE;
2894

2895 2896 2897 2898
                VBOX_RELEASE(medium);
                VBOX_RELEASE(storageController);
                diskCount++;
            }
2899

2900
            vboxArrayRelease(&mediumAttachments);
2901

2902 2903 2904 2905 2906 2907 2908 2909
            /* cleanup on error */
            if (error) {
                for (i = 0; i < def->ndisks; i++) {
                    VIR_FREE(def->disks[i]);
                }
                VIR_FREE(def->disks);
                def->ndisks = 0;
            }
2910

2911
#endif /* VBOX_API_VERSION >= 3001 */
2912

M
Matthias Bolte 已提交
2913 2914 2915 2916 2917 2918 2919 2920 2921
            /* shared folders */
            vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER;

            def->nfss = 0;

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

            if (sharedFolders.count > 0) {
2922
                if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0)
M
Matthias Bolte 已提交
2923 2924 2925 2926 2927 2928 2929 2930 2931 2932
                    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;

2933
                    if (VIR_ALLOC(def->fss[i]) < 0)
M
Matthias Bolte 已提交
2934 2935 2936 2937 2938 2939
                        goto sharedFoldersCleanup;

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

                    sharedFolder->vtbl->GetHostPath(sharedFolder, &hostPathUtf16);
                    VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath);
2940 2941 2942
                    if (VIR_STRDUP(def->fss[i]->src, hostPath) < 0) {
                        VBOX_UTF8_FREE(hostPath);
                        VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2943 2944
                        goto sharedFoldersCleanup;
                    }
2945 2946
                    VBOX_UTF8_FREE(hostPath);
                    VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2947 2948 2949

                    sharedFolder->vtbl->GetName(sharedFolder, &nameUtf16);
                    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
2950 2951 2952
                    if (VIR_STRDUP(def->fss[i]->dst, name) < 0) {
                        VBOX_UTF8_FREE(name);
                        VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2953 2954
                        goto sharedFoldersCleanup;
                    }
2955 2956
                    VBOX_UTF8_FREE(name);
                    VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967

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

                    ++def->nfss;
                }
            }

sharedFoldersCleanup:
            vboxArrayRelease(&sharedFolders);

2968 2969 2970 2971 2972
            /* dump network cards if present */
            def->nnets = 0;
            /* Get which network cards are enabled */
            for (i = 0; i < netAdpCnt; i++) {
                INetworkAdapter *adapter = NULL;
2973

2974 2975 2976
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
2977

2978 2979 2980 2981
                    adapter->vtbl->GetEnabled(adapter, &enabled);
                    if (enabled) {
                        def->nnets++;
                    }
2982

2983 2984 2985
                    VBOX_RELEASE(adapter);
                }
            }
2986

2987 2988 2989
            /* 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++) {
2990
                    ignore_value(VIR_ALLOC(def->nets[i]));
2991 2992
                }
            }
2993

2994
            /* Now get the details about the network cards here */
2995
            for (i = 0; netAdpIncCnt < def->nnets && i < netAdpCnt; i++) {
2996
                INetworkAdapter *adapter = NULL;
2997

2998 2999 3000
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
3001

3002 3003 3004 3005 3006 3007 3008
                    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};
3009

3010 3011
                        adapter->vtbl->GetAttachmentType(adapter, &attachmentType);
                        if (attachmentType == NetworkAttachmentType_NAT) {
3012

3013
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
3014

3015 3016 3017
                        } else if (attachmentType == NetworkAttachmentType_Bridged) {
                            PRUnichar *hostIntUtf16 = NULL;
                            char *hostInt           = NULL;
3018

3019
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
3020

3021
#if VBOX_API_VERSION < 4001
3022
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
3023 3024 3025
#else /* VBOX_API_VERSION >= 4001 */
                            adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16);
#endif /* VBOX_API_VERSION >= 4001 */
3026

3027
                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
3028
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.bridge.brname, hostInt));
3029

3030 3031
                            VBOX_UTF8_FREE(hostInt);
                            VBOX_UTF16_FREE(hostIntUtf16);
3032

3033 3034 3035
                        } else if (attachmentType == NetworkAttachmentType_Internal) {
                            PRUnichar *intNetUtf16 = NULL;
                            char *intNet           = NULL;
3036

3037 3038 3039 3040 3041
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL;

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

                            VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet);
3042
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.internal.name, intNet));
3043 3044 3045 3046 3047 3048 3049 3050 3051 3052

                            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;

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

                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
3060
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.network.name, hostInt));
3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073

                            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) {
3074
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C970A"));
3075
                        } else if (adapterType == NetworkAdapterType_Am79C973) {
3076
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C973"));
3077
                        } else if (adapterType == NetworkAdapterType_I82540EM) {
3078
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82540EM"));
3079
                        } else if (adapterType == NetworkAdapterType_I82545EM) {
3080
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82545EM"));
3081
                        } else if (adapterType == NetworkAdapterType_I82543GC) {
3082
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82543GC"));
3083 3084
#if VBOX_API_VERSION >= 3001
                        } else if (adapterType == NetworkAdapterType_Virtio) {
3085
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "virtio"));
3086
#endif /* VBOX_API_VERSION >= 3001 */
3087 3088
                        }

3089 3090 3091 3092 3093 3094 3095 3096 3097
                        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 ... */
3098
                        if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0)
3099 3100 3101 3102 3103 3104
                        {}

                        netAdpIncCnt++;

                        VBOX_UTF16_FREE(MACAddressUtf16);
                        VBOX_UTF8_FREE(MACAddress);
3105
                    }
3106 3107

                    VBOX_RELEASE(adapter);
3108
                }
3109
            }
3110

3111
            /* dump sound card if active */
3112

3113 3114 3115
            /* Set def->nsounds to one as VirtualBox currently supports
             * only one sound card
             */
3116

3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143
            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);
            }
3144

3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168
#if VBOX_API_VERSION < 3001
            /* dump CDROM/DVD if the drive is attached and has DVD/CD in it */
            machine->vtbl->GetDVDDrive(machine, &dvdDrive);
            if (dvdDrive) {
                PRUint32 state = DriveState_Null;

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

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

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

                        def->ndisks++;
                        if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
                            if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
                                def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
                                def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_IDE;
                                def->disks[def->ndisks - 1]->type = VIR_DOMAIN_DISK_TYPE_FILE;
3169
                                def->disks[def->ndisks - 1]->readonly = true;
3170 3171 3172
                                ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->src, location));
                                ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "hdc"));
                                def->ndisks--;
3173
                            } else {
3174
                                def->ndisks--;
3175 3176
                            }
                        } else {
3177
                            def->ndisks--;
3178
                        }
3179 3180 3181 3182

                        VBOX_UTF8_FREE(location);
                        VBOX_UTF16_FREE(locationUtf16);
                        VBOX_MEDIUM_RELEASE(dvdImage);
3183 3184
                    }
                }
3185 3186
                VBOX_RELEASE(dvdDrive);
            }
3187

3188 3189 3190 3191 3192 3193 3194
            /* 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) {
3195 3196
                    PRUint32 state = DriveState_Null;

3197
                    floppyDrive->vtbl->GetState(floppyDrive, &state);
3198
                    if (state == DriveState_ImageMounted) {
3199
                        IFloppyImage *floppyImage = NULL;
3200

3201 3202
                        floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage);
                        if (floppyImage) {
3203 3204 3205
                            PRUnichar *locationUtf16 = NULL;
                            char *location           = NULL;

3206 3207
                            floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16);
                            VBOX_UTF16_TO_UTF8(locationUtf16, &location);
3208 3209 3210 3211

                            def->ndisks++;
                            if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
                                if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
3212 3213
                                    def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                                    def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
3214
                                    def->disks[def->ndisks - 1]->type = VIR_DOMAIN_DISK_TYPE_FILE;
3215
                                    def->disks[def->ndisks - 1]->readonly = false;
3216 3217 3218
                                    ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->src, location));
                                    ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "fda"));
                                    def->ndisks--;
3219 3220 3221 3222 3223 3224 3225
                                } else {
                                    def->ndisks--;
                                }
                            } else {
                                def->ndisks--;
                            }

3226 3227 3228
                            VBOX_UTF8_FREE(location);
                            VBOX_UTF16_FREE(locationUtf16);
                            VBOX_MEDIUM_RELEASE(floppyImage);
3229 3230 3231 3232
                        }
                    }
                }

3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245
                VBOX_RELEASE(floppyDrive);
            }
#else  /* VBOX_API_VERSION >= 3001 */
#endif /* VBOX_API_VERSION >= 3001 */

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

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

3248
                    serialPort->vtbl->GetEnabled(serialPort, &enabled);
3249
                    if (enabled) {
3250
                        def->nserials++;
3251 3252
                    }

3253
                    VBOX_RELEASE(serialPort);
3254
                }
3255
            }
3256

3257 3258 3259
            /* 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++) {
3260
                    ignore_value(VIR_ALLOC(def->serials[i]));
3261 3262
                }
            }
3263

3264
            /* Now get the details about the serial ports here */
3265 3266 3267
            for (i = 0;
                 serialPortIncCount < def->nserials && i < serialPortCount;
                 i++) {
3268
                ISerialPort *serialPort = NULL;
3269

3270 3271 3272
                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
                    PRBool enabled = PR_FALSE;
3273

3274 3275 3276 3277 3278 3279 3280 3281 3282 3283
                    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) {
3284
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
3285
                        } else if (hostMode == PortMode_HostDevice) {
3286
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
3287 3288
#if VBOX_API_VERSION >= 3000
                        } else if (hostMode == PortMode_RawFile) {
3289
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3290 3291
#endif /* VBOX_API_VERSION >= 3000 */
                        } else {
3292
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL;
3293
                        }
3294

3295
                        def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
3296

3297 3298 3299 3300 3301 3302 3303
                        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;
                        }
3304

3305
                        serialPort->vtbl->GetPath(serialPort, &pathUtf16);
3306

3307 3308
                        if (pathUtf16) {
                            VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3309
                            ignore_value(VIR_STRDUP(def->serials[serialPortIncCount]->source.data.file.path, path));
3310 3311
                        }

3312 3313 3314 3315
                        serialPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3316 3317
                    }

3318 3319 3320
                    VBOX_RELEASE(serialPort);
                }
            }
3321

3322 3323 3324 3325 3326
            /* dump parallel ports if active */
            def->nparallels = 0;
            /* Get which parallel ports are enabled/active */
            for (i = 0; i < parallelPortCount; i++) {
                IParallelPort *parallelPort = NULL;
3327

3328 3329 3330
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3331

3332 3333 3334
                    parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                    if (enabled) {
                        def->nparallels++;
3335
                    }
3336 3337

                    VBOX_RELEASE(parallelPort);
3338
                }
3339
            }
3340

3341 3342 3343
            /* 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++) {
3344
                    ignore_value(VIR_ALLOC(def->parallels[i]));
3345
                }
3346
            }
3347

3348
            /* Now get the details about the parallel ports here */
3349 3350 3351 3352
            for (i = 0;
                 parallelPortIncCount < def->nparallels &&
                     i < parallelPortCount;
                 i++) {
3353
                IParallelPort *parallelPort = NULL;
3354

3355 3356 3357
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3358

3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372
                    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;
                        }
3373

3374
                        def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3375
                        def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
3376

3377
                        parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);
3378

3379
                        VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3380
                        ignore_value(VIR_STRDUP(def->parallels[parallelPortIncCount]->source.data.file.path, path));
3381

3382 3383 3384 3385
                        parallelPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3386
                    }
3387 3388

                    VBOX_RELEASE(parallelPort);
3389
                }
3390
            }
3391

3392
            /* dump USB devices/filters if active */
3393
            vboxHostDeviceGetXMLDesc(data, def, machine);
3394 3395 3396 3397 3398

            /* all done so set gotAllABoutDef and pass def to virDomainDefFormat
             * to generate XML for it
             */
            gotAllABoutDef = 0;
3399
        }
3400 3401
        VBOX_RELEASE(machine);
        machine = NULL;
3402 3403 3404
    }

    if (gotAllABoutDef == 0)
3405
        ret = virDomainDefFormat(def, flags);
3406 3407

cleanup:
3408
    vboxIIDUnalloc(&iid);
3409 3410 3411 3412
    virDomainDefFree(def);
    return ret;
}

3413
static int vboxConnectListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
3414
    VBOX_OBJECT_CHECK(conn, int, -1);
3415
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3416 3417 3418
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    PRUint32 state;
3419
    nsresult rc;
3420
    size_t i, j;
3421

3422
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3423
    if (NS_FAILED(rc)) {
3424 3425 3426
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3427 3428
        goto cleanup;
    }
3429

3430 3431
    memset(names, 0, sizeof(names[i]) * maxnames);

3432 3433 3434
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) {
        IMachine *machine = machines.items[i];
3435 3436 3437 3438 3439 3440

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3441 3442
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3443 3444
                    machine->vtbl->GetName(machine, &machineNameUtf16);
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
3445 3446 3447
                    if (VIR_STRDUP(names[j], machineName) < 0) {
                        VBOX_UTF16_FREE(machineNameUtf16);
                        VBOX_UTF8_FREE(machineName);
3448
                        for (j = 0; j < maxnames; j++)
3449 3450 3451
                            VIR_FREE(names[j]);
                        ret = -1;
                        goto cleanup;
3452
                    }
3453 3454
                    VBOX_UTF16_FREE(machineNameUtf16);
                    VBOX_UTF8_FREE(machineName);
3455
                    j++;
3456
                    ret++;
3457 3458 3459 3460 3461 3462
                }
            }
        }
    }

cleanup:
3463
    vboxArrayRelease(&machines);
3464 3465 3466
    return ret;
}

3467
static int vboxConnectNumOfDefinedDomains(virConnectPtr conn) {
3468
    VBOX_OBJECT_CHECK(conn, int, -1);
3469
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3470
    PRUint32 state       = MachineState_Null;
3471
    nsresult rc;
3472
    size_t i;
3473

3474
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3475
    if (NS_FAILED(rc)) {
3476 3477 3478
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3479 3480
        goto cleanup;
    }
3481

3482 3483 3484
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3485 3486 3487 3488 3489 3490

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3491 3492
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3493
                    ret++;
3494 3495 3496 3497 3498 3499
                }
            }
        }
    }

cleanup:
3500
    vboxArrayRelease(&machines);
3501 3502 3503
    return ret;
}

E
Eric Blake 已提交
3504 3505

static int
3506
vboxStartMachine(virDomainPtr dom, int maxDomID, IMachine *machine,
3507
                 vboxIID *iid ATTRIBUTE_UNUSED /* >= 4.0 */)
E
Eric Blake 已提交
3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533
{
    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);

3534
        if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
E
Eric Blake 已提交
3535 3536 3537 3538 3539 3540 3541 3542 3543 3544

            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 已提交
3545
                if (strlen(valueDisplayUtf8) <= 0)
E
Eric Blake 已提交
3546 3547 3548 3549 3550
                    VBOX_UTF8_FREE(valueDisplayUtf8);
            }

            if (STREQ(valueTypeUtf8, "sdl")) {
                sdlPresent = 1;
3551 3552 3553 3554 3555
                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 已提交
3556 3557 3558 3559 3560
                }
            }

            if (STREQ(valueTypeUtf8, "gui")) {
                guiPresent = 1;
3561 3562 3563 3564 3565
                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 已提交
3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585
                }
            }
        }

        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 已提交
3586
    VBOX_UTF8_FREE(valueDisplayUtf8);
E
Eric Blake 已提交
3587 3588 3589

    if (guiPresent) {
        if (guiDisplay) {
E
Eric Blake 已提交
3590
            char *displayutf8;
3591
            if (virAsprintf(&displayutf8, "DISPLAY=%s", guiDisplay) >= 0) {
E
Eric Blake 已提交
3592 3593 3594
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3595 3596 3597 3598 3599 3600 3601 3602
            VIR_FREE(guiDisplay);
        }

        VBOX_UTF8_TO_UTF16("gui", &sessionType);
    }

    if (sdlPresent) {
        if (sdlDisplay) {
E
Eric Blake 已提交
3603
            char *displayutf8;
3604
            if (virAsprintf(&displayutf8, "DISPLAY=%s", sdlDisplay) >= 0) {
E
Eric Blake 已提交
3605 3606 3607
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3608 3609 3610 3611 3612 3613 3614 3615 3616 3617
            VIR_FREE(sdlDisplay);
        }

        VBOX_UTF8_TO_UTF16("sdl", &sessionType);
    }

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

3618
#if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
3619 3620
    rc = data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
                                                data->vboxSession,
3621
                                                iid->value,
E
Eric Blake 已提交
3622 3623
                                                sessionType,
                                                env,
3624
                                                &progress);
3625 3626 3627 3628 3629
#else /* VBOX_API_VERSION >= 4000 */
    rc = machine->vtbl->LaunchVMProcess(machine, data->vboxSession,
                                        sessionType, env, &progress);
#endif /* VBOX_API_VERSION >= 4000 */

E
Eric Blake 已提交
3630
    if (NS_FAILED(rc)) {
3631 3632
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("OpenRemoteSession/LaunchVMProcess failed, domain can't be started"));
E
Eric Blake 已提交
3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652
        ret = -1;
    } else {
        PRBool completed = 0;
#if VBOX_API_VERSION == 2002
        nsresult resultCode;
#else
        PRInt32  resultCode;
#endif
        progress->vtbl->WaitForCompletion(progress, -1);
        rc = progress->vtbl->GetCompleted(progress, &completed);
        if (NS_FAILED(rc)) {
            /* error */
            ret = -1;
        }
        progress->vtbl->GetResultCode(progress, &resultCode);
        if (NS_FAILED(resultCode)) {
            /* error */
            ret = -1;
        } else {
            /* all ok set the domid */
3653
            dom->id = maxDomID + 1;
E
Eric Blake 已提交
3654 3655 3656 3657 3658 3659
            ret = 0;
        }
    }

    VBOX_RELEASE(progress);

3660
    VBOX_SESSION_CLOSE();
E
Eric Blake 已提交
3661 3662 3663 3664 3665 3666 3667

    VBOX_UTF16_FREE(env);
    VBOX_UTF16_FREE(sessionType);

    return ret;
}

3668
static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) {
3669
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
3670
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3671
    unsigned char uuid[VIR_UUID_BUFLEN] = {0};
3672
    nsresult rc;
3673
    size_t i = 0;
3674

3675 3676
    virCheckFlags(0, -1);

3677
    if (!dom->name) {
3678 3679
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Error while reading the domain name"));
3680 3681 3682
        goto cleanup;
    }

3683
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3684
    if (NS_FAILED(rc)) {
3685 3686
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
3687 3688
        goto cleanup;
    }
3689

3690 3691
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3692
        PRBool isAccessible = PR_FALSE;
3693

3694 3695
        if (!machine)
            continue;
3696

3697 3698
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
3699
            vboxIID iid = VBOX_IID_INITIALIZER;
3700

3701 3702
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
3703
                continue;
3704
            vboxIIDToUUID(&iid, uuid);
3705

3706
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
3707 3708 3709
                PRUint32 state = MachineState_Null;
                machine->vtbl->GetState(machine, &state);

3710 3711 3712
                if ((state == MachineState_PoweredOff) ||
                    (state == MachineState_Saved) ||
                    (state == MachineState_Aborted)) {
3713
                    ret = vboxStartMachine(dom, i, machine, &iid);
3714
                } else {
3715
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3716 3717 3718
                                   _("machine is not in "
                                     "poweroff|saved|aborted state, so "
                                     "couldn't start it"));
3719
                    ret = -1;
3720 3721
                }
            }
3722
            vboxIIDUnalloc(&iid);
3723 3724
            if (ret != -1)
                break;
3725 3726 3727
        }
    }

3728
    /* Do the cleanup and take care you dont leak any memory */
3729
    vboxArrayRelease(&machines);
3730

3731 3732 3733 3734
cleanup:
    return ret;
}

3735 3736 3737 3738
static int vboxDomainCreate(virDomainPtr dom) {
    return vboxDomainCreateWithFlags(dom, 0);
}

E
Eric Blake 已提交
3739 3740 3741 3742 3743 3744
static void
vboxSetBootDeviceOrder(virDomainDefPtr def, vboxGlobalData *data,
                       IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 maxBootPosition            = 0;
3745
    size_t i = 0;
3746

3747
    VIR_DEBUG("def->os.type             %s", def->os.type);
3748
    VIR_DEBUG("def->os.arch             %s", virArchToString(def->os.arch));
3749
    VIR_DEBUG("def->os.machine          %s", def->os.machine);
3750
    VIR_DEBUG("def->os.nBootDevs        %zu", def->os.nBootDevs);
3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762
    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);
3763

E
Eric Blake 已提交
3764 3765 3766 3767 3768 3769
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxBootPosition(systemProperties,
                                                   &maxBootPosition);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
3770
    }
3771

E
Eric Blake 已提交
3772 3773 3774
    /* Clear the defaults first */
    for (i = 0; i < maxBootPosition; i++) {
        machine->vtbl->SetBootOrder(machine, i+1, DeviceType_Null);
3775
    }
3776

E
Eric Blake 已提交
3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787
    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;
3788
        }
E
Eric Blake 已提交
3789
        machine->vtbl->SetBootOrder(machine, i+1, device);
3790
    }
E
Eric Blake 已提交
3791
}
3792

E
Eric Blake 已提交
3793 3794 3795
static void
vboxAttachDrives(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
3796
    size_t i;
E
Eric Blake 已提交
3797
    nsresult rc;
3798 3799

#if VBOX_API_VERSION < 3001
E
Eric Blake 已提交
3800 3801 3802 3803
    if (def->ndisks == 0)
        return;

    for (i = 0; i < def->ndisks; i++) {
3804 3805 3806 3807 3808 3809 3810
        VIR_DEBUG("disk(%zu) type:       %d", i, def->disks[i]->type);
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
        VIR_DEBUG("disk(%zu) src:        %s", i, def->disks[i]->src);
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
        VIR_DEBUG("disk(%zu) driverName: %s", i, def->disks[i]->driverName);
        VIR_DEBUG("disk(%zu) driverType: %s", i,
3811
                  virStorageFileFormatTypeToString(def->disks[i]->format));
3812 3813
        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 已提交
3814
                                             ? "True" : "False"));
3815
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->shared
E
Eric Blake 已提交
3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827
                                             ? "True" : "False"));

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

E
Eric Blake 已提交
3829 3830 3831 3832
                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                if (dvdDrive) {
                    IDVDImage *dvdImage          = NULL;
                    PRUnichar *dvdfileUtf16      = NULL;
3833 3834
                    vboxIID dvduuid = VBOX_IID_INITIALIZER;
                    vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
3835

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

E
Eric Blake 已提交
3838 3839 3840 3841 3842
                    data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                      dvdfileUtf16, &dvdImage);
                    if (!dvdImage) {
                        data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                          dvdfileUtf16,
3843
                                                          dvdemptyuuid.value,
E
Eric Blake 已提交
3844 3845 3846 3847
                                                          &dvdImage);
                    }
                    if (dvdImage) {
                        rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage,
3848
                                                           &dvduuid.value);
E
Eric Blake 已提交
3849
                        if (NS_FAILED(rc)) {
3850 3851 3852 3853
                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                           _("can't get the uuid of the file to "
                                             "be attached to cdrom: %s, rc=%08x"),
                                           def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
3854
                        } else {
3855
                            rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
E
Eric Blake 已提交
3856
                            if (NS_FAILED(rc)) {
3857 3858 3859
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("could not attach the file to cdrom: %s, rc=%08x"),
                                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
3860
                            } else {
3861
                                DEBUGIID("CD/DVDImage UUID:", dvduuid.value);
3862
                            }
3863
                        }
E
Eric Blake 已提交
3864 3865

                        VBOX_MEDIUM_RELEASE(dvdImage);
3866
                    }
3867
                    vboxIIDUnalloc(&dvduuid);
E
Eric Blake 已提交
3868 3869 3870 3871 3872 3873 3874 3875 3876 3877
                    VBOX_UTF16_FREE(dvdfileUtf16);
                    VBOX_RELEASE(dvdDrive);
                }
            } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
            if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                def->disks[i]->src != NULL) {
                IHardDisk *hardDisk     = NULL;
                PRUnichar *hddfileUtf16 = NULL;
3878
                vboxIID hdduuid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
3879 3880 3881 3882 3883 3884
                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
                 */
3885

E
Eric Blake 已提交
3886 3887
                VBOX_UTF8_TO_UTF16(def->disks[i]->src, &hddfileUtf16);
                VBOX_UTF8_TO_UTF16("", &hddEmpty);
3888

E
Eric Blake 已提交
3889 3890
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16,
                                                  &hardDisk);
3891

E
Eric Blake 已提交
3892
                if (!hardDisk) {
3893
# if VBOX_API_VERSION == 2002
E
Eric Blake 已提交
3894 3895 3896 3897
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      &hardDisk);
3898
# else
E
Eric Blake 已提交
3899 3900 3901 3902 3903 3904 3905 3906
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      0,
                                                      hddEmpty,
                                                      0,
                                                      hddEmpty,
                                                      &hardDisk);
3907
# endif
E
Eric Blake 已提交
3908
                }
3909

E
Eric Blake 已提交
3910 3911
                if (hardDisk) {
                    rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk,
3912
                                                       &hdduuid.value);
E
Eric Blake 已提交
3913
                    if (NS_FAILED(rc)) {
3914 3915 3916 3917
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("can't get the uuid of the file to be "
                                         "attached as harddisk: %s, rc=%08x"),
                                       def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
3918 3919 3920 3921
                    } else {
                        if (def->disks[i]->readonly) {
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Immutable);
3922
                            VIR_DEBUG("setting harddisk to readonly");
E
Eric Blake 已提交
3923 3924 3925
                        } else if (!def->disks[i]->readonly) {
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Normal);
3926
                            VIR_DEBUG("setting harddisk type to normal");
E
Eric Blake 已提交
3927 3928 3929
                        }
                        if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                            if (STREQ(def->disks[i]->dst, "hdc")) {
3930
                                VIR_DEBUG("Not connecting harddisk to hdc as hdc"
E
Eric Blake 已提交
3931
                                       " is taken by CD/DVD Drive");
3932
                            } else {
E
Eric Blake 已提交
3933 3934 3935 3936
                                PRInt32 channel          = 0;
                                PRInt32 device           = 0;
                                PRUnichar *hddcnameUtf16 = NULL;

3937 3938
                                char *hddcname;
                                ignore_value(VIR_STRDUP(hddcname, "IDE"));
E
Eric Blake 已提交
3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950
                                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;
3951
                                }
E
Eric Blake 已提交
3952 3953

                                rc = machine->vtbl->AttachHardDisk(machine,
3954
                                                                   hdduuid.value,
E
Eric Blake 已提交
3955 3956 3957 3958 3959 3960
                                                                   hddcnameUtf16,
                                                                   channel,
                                                                   device);
                                VBOX_UTF16_FREE(hddcnameUtf16);

                                if (NS_FAILED(rc)) {
3961 3962 3963 3964
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file as "
                                                     "harddisk: %s, rc=%08x"),
                                                   def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
3965
                                } else {
3966
                                    DEBUGIID("Attached HDD with UUID", hdduuid.value);
3967 3968 3969
                                }
                            }
                        }
3970
                    }
E
Eric Blake 已提交
3971 3972
                    VBOX_MEDIUM_RELEASE(hardDisk);
                }
3973
                vboxIIDUnalloc(&hdduuid);
E
Eric Blake 已提交
3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987
                VBOX_UTF16_FREE(hddEmpty);
                VBOX_UTF16_FREE(hddfileUtf16);
            } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
            if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                def->disks[i]->src != NULL) {
                IFloppyDrive *floppyDrive;
                machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                if (floppyDrive) {
                    rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1);
                    if (NS_SUCCEEDED(rc)) {
                        IFloppyImage *floppyImage   = NULL;
                        PRUnichar *fdfileUtf16      = NULL;
3988 3989
                        vboxIID fduuid = VBOX_IID_INITIALIZER;
                        vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
3990

E
Eric Blake 已提交
3991 3992 3993 3994
                        VBOX_UTF8_TO_UTF16(def->disks[i]->src, &fdfileUtf16);
                        rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                  fdfileUtf16,
                                                                  &floppyImage);
3995

E
Eric Blake 已提交
3996 3997 3998
                        if (!floppyImage) {
                            data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                 fdfileUtf16,
3999
                                                                 fdemptyuuid.value,
E
Eric Blake 已提交
4000 4001
                                                                 &floppyImage);
                        }
4002

E
Eric Blake 已提交
4003 4004
                        if (floppyImage) {
                            rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage,
4005
                                                                  &fduuid.value);
E
Eric Blake 已提交
4006
                            if (NS_FAILED(rc)) {
4007 4008 4009 4010
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("can't get the uuid of the file to "
                                                 "be attached to floppy drive: %s, rc=%08x"),
                                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4011 4012
                            } else {
                                rc = floppyDrive->vtbl->MountImage(floppyDrive,
4013
                                                                   fduuid.value);
E
Eric Blake 已提交
4014
                                if (NS_FAILED(rc)) {
4015 4016 4017 4018
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file to "
                                                     "floppy drive: %s, rc=%08x"),
                                                   def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4019
                                } else {
4020
                                    DEBUGIID("floppyImage UUID", fduuid.value);
4021 4022
                                }
                            }
E
Eric Blake 已提交
4023
                            VBOX_MEDIUM_RELEASE(floppyImage);
4024
                        }
4025
                        vboxIIDUnalloc(&fduuid);
E
Eric Blake 已提交
4026
                        VBOX_UTF16_FREE(fdfileUtf16);
4027
                    }
E
Eric Blake 已提交
4028
                    VBOX_RELEASE(floppyDrive);
4029
                }
E
Eric Blake 已提交
4030
            } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
4031
            }
4032
        }
E
Eric Blake 已提交
4033
    }
4034
#else  /* VBOX_API_VERSION >= 3001 */
E
Eric Blake 已提交
4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046
    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 */
4047
    {
E
Eric Blake 已提交
4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082
        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);
    }
4083

E
Eric Blake 已提交
4084
    for (i = 0; i < def->ndisks && !error; i++) {
4085 4086 4087 4088 4089 4090 4091
        VIR_DEBUG("disk(%zu) type:       %d", i, def->disks[i]->type);
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
        VIR_DEBUG("disk(%zu) src:        %s", i, def->disks[i]->src);
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
        VIR_DEBUG("disk(%zu) driverName: %s", i, def->disks[i]->driverName);
        VIR_DEBUG("disk(%zu) driverType: %s", i,
4092
                  virStorageFileFormatTypeToString(def->disks[i]->format));
4093 4094
        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 已提交
4095
                                             ? "True" : "False"));
4096
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->shared
E
Eric Blake 已提交
4097 4098 4099 4100 4101 4102 4103 4104 4105
                                             ? "True" : "False"));

        if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE &&
            def->disks[i]->src != NULL) {
            IMedium   *medium          = NULL;
            PRUnichar *mediumUUID      = NULL;
            PRUnichar *mediumFileUtf16 = NULL;
            PRUint32   storageBus      = StorageBus_Null;
            PRUint32   deviceType      = DeviceType_Null;
4106
# if VBOX_API_VERSION >= 4000
4107
            PRUint32   accessMode      = AccessMode_ReadOnly;
4108
# endif
E
Eric Blake 已提交
4109 4110 4111 4112 4113 4114 4115 4116
            PRInt32    deviceInst      = 0;
            PRInt32    devicePort      = 0;
            PRInt32    deviceSlot      = 0;

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

            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                deviceType = DeviceType_HardDisk;
4117
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4118 4119
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj,
                                                  mediumFileUtf16, &medium);
4120 4121
# else
                accessMode = AccessMode_ReadWrite;
4122
# endif
E
Eric Blake 已提交
4123 4124
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                deviceType = DeviceType_DVD;
4125
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4126 4127
                data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                  mediumFileUtf16, &medium);
4128 4129
# else
                accessMode = AccessMode_ReadOnly;
4130
# endif
E
Eric Blake 已提交
4131 4132
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                deviceType = DeviceType_Floppy;
4133
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4134 4135
                data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                     mediumFileUtf16, &medium);
4136 4137
# else
                accessMode = AccessMode_ReadWrite;
4138
# endif
E
Eric Blake 已提交
4139 4140 4141 4142
            } else {
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4143

4144
# if VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
4145 4146
            data->vboxObj->vtbl->FindMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, &medium);
4147 4148 4149
# elif VBOX_API_VERSION >= 4002
            data->vboxObj->vtbl->OpenMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, accessMode, PR_FALSE, &medium);
4150 4151
# endif

E
Eric Blake 已提交
4152 4153
            if (!medium) {
                PRUnichar *mediumEmpty = NULL;
4154

E
Eric Blake 已提交
4155
                VBOX_UTF8_TO_UTF16("", &mediumEmpty);
4156

4157
# if VBOX_API_VERSION < 4000
4158
                if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
4159 4160 4161 4162 4163 4164 4165 4166
                    rc = data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                           mediumFileUtf16,
                                                           AccessMode_ReadWrite,
                                                           false,
                                                           mediumEmpty,
                                                           false,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
4167 4168
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_CDROM) {
4169 4170 4171 4172
                    rc = data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                           mediumFileUtf16,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
4173 4174
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
4175 4176 4177 4178 4179 4180
                    rc = data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                              mediumFileUtf16,
                                                              mediumEmpty,
                                                              &medium);
                } else {
                    rc = 0;
4181
                }
4182
# elif VBOX_API_VERSION == 4000
4183 4184 4185 4186
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     &medium);
4187 4188 4189 4190 4191 4192 4193
# elif VBOX_API_VERSION >= 4001
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     false,
                                                     &medium);
# endif /* VBOX_API_VERSION >= 4001 */
4194

E
Eric Blake 已提交
4195 4196
                VBOX_UTF16_FREE(mediumEmpty);
            }
4197

E
Eric Blake 已提交
4198
            if (!medium) {
4199 4200 4201 4202
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to attach the following disk/dvd/floppy "
                                 "to the machine: %s, rc=%08x"),
                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4203 4204 4205
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4206

E
Eric Blake 已提交
4207 4208
            rc = medium->vtbl->GetId(medium, &mediumUUID);
            if (NS_FAILED(rc)) {
4209 4210 4211 4212
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("can't get the uuid of the file to be attached "
                                 "as harddisk/dvd/floppy: %s, rc=%08x"),
                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4213 4214 4215 4216
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4217

E
Eric Blake 已提交
4218 4219 4220
            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                if (def->disks[i]->readonly) {
                    medium->vtbl->SetType(medium, MediumType_Immutable);
4221
                    VIR_DEBUG("setting harddisk to immutable");
E
Eric Blake 已提交
4222 4223
                } else if (!def->disks[i]->readonly) {
                    medium->vtbl->SetType(medium, MediumType_Normal);
4224
                    VIR_DEBUG("setting harddisk type to normal");
4225
                }
E
Eric Blake 已提交
4226
            }
4227

E
Eric Blake 已提交
4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240
            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;
            }
4241

E
Eric Blake 已提交
4242 4243 4244 4245 4246 4247 4248 4249
            /* get the device details i.e instance, port and slot */
            if (!vboxGetDeviceDetails(def->disks[i]->dst,
                                      maxPortPerInst,
                                      maxSlotPerPort,
                                      storageBus,
                                      &deviceInst,
                                      &devicePort,
                                      &deviceSlot)) {
4250
                virReportError(VIR_ERR_INTERNAL_ERROR,
4251 4252 4253
                               _("can't get the port/slot number of "
                                 "harddisk/dvd/floppy to be attached: "
                                 "%s, rc=%08x"),
4254
                               def->disks[i]->src, (unsigned)rc);
4255 4256 4257
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumUUID);
                VBOX_UTF16_FREE(mediumFileUtf16);
E
Eric Blake 已提交
4258 4259 4260 4261 4262 4263 4264 4265 4266
                continue;
            }

            /* attach the harddisk/dvd/Floppy to the storage controller */
            rc = machine->vtbl->AttachDevice(machine,
                                             storageCtlName,
                                             devicePort,
                                             deviceSlot,
                                             deviceType,
4267
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4268
                                             mediumUUID);
4269 4270 4271
# else /* VBOX_API_VERSION >= 4000 */
                                             medium);
# endif /* VBOX_API_VERSION >= 4000 */
E
Eric Blake 已提交
4272 4273

            if (NS_FAILED(rc)) {
4274
                virReportError(VIR_ERR_INTERNAL_ERROR,
4275 4276
                               _("could not attach the file as "
                                 "harddisk/dvd/floppy: %s, rc=%08x"),
4277
                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4278 4279
            } else {
                DEBUGIID("Attached HDD/DVD/Floppy with UUID", mediumUUID);
4280
            }
E
Eric Blake 已提交
4281 4282 4283 4284 4285

            VBOX_RELEASE(medium);
            VBOX_UTF16_FREE(mediumUUID);
            VBOX_UTF16_FREE(mediumFileUtf16);
            VBOX_UTF16_FREE(storageCtlName);
4286 4287 4288
        }
    }
#endif /* VBOX_API_VERSION >= 3001 */
E
Eric Blake 已提交
4289
}
4290

E
Eric Blake 已提交
4291 4292 4293 4294
static void
vboxAttachSound(virDomainDefPtr def, IMachine *machine)
{
    nsresult rc;
4295

E
Eric Blake 已提交
4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311
    /* 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);
4312
                }
4313
            }
E
Eric Blake 已提交
4314
            VBOX_RELEASE(audioAdapter);
4315
        }
E
Eric Blake 已提交
4316 4317 4318 4319 4320 4321 4322
    }
}

static void
vboxAttachNetwork(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
4323 4324 4325
#if VBOX_API_VERSION >= 4001
    PRUint32 chipsetType                = ChipsetType_Null;
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4326
    PRUint32 networkAdapterCount        = 0;
4327
    size_t i = 0;
E
Eric Blake 已提交
4328

4329 4330 4331 4332
#if VBOX_API_VERSION >= 4001
    machine->vtbl->GetChipsetType(machine, &chipsetType);
#endif /* VBOX_API_VERSION >= 4001 */

E
Eric Blake 已提交
4333 4334
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
4335
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4336 4337
        systemProperties->vtbl->GetNetworkAdapterCount(systemProperties,
                                                       &networkAdapterCount);
4338 4339 4340 4341
#else  /* VBOX_API_VERSION >= 4000 */
        systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType,
                                                      &networkAdapterCount);
#endif /* VBOX_API_VERSION >= 4000 */
E
Eric Blake 已提交
4342 4343 4344 4345
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }

4346
    VIR_DEBUG("Number of Network Cards to be connected: %zu", def->nnets);
4347
    VIR_DEBUG("Number of Network Cards available: %d", networkAdapterCount);
E
Eric Blake 已提交
4348 4349 4350 4351 4352 4353 4354

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

4355
        virMacAddrFormat(&def->nets[i]->mac, macaddr);
E
Eric Blake 已提交
4356 4357
        snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
                 "%02X%02X%02X%02X%02X%02X",
4358 4359 4360 4361 4362 4363
                 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 已提交
4364 4365
        macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';

4366 4367 4368 4369
        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 已提交
4370
        if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4371
            VIR_DEBUG("NIC(%zu): name:    %s", i, def->nets[i]->data.network.name);
E
Eric Blake 已提交
4372
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
4373
            VIR_DEBUG("NIC(%zu): name:   %s", i, def->nets[i]->data.internal.name);
E
Eric Blake 已提交
4374
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
4375
            VIR_DEBUG("NIC(%zu): NAT.", i);
E
Eric Blake 已提交
4376
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
4377 4378 4379
            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);
4380 4381
        }

E
Eric Blake 已提交
4382 4383 4384 4385 4386
        machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
        if (adapter) {
            PRUnichar *MACAddress = NULL;

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

E
Eric Blake 已提交
4388
            if (def->nets[i]->model) {
E
Eric Blake 已提交
4389
                if (STRCASEEQ(def->nets[i]->model, "Am79C970A")) {
E
Eric Blake 已提交
4390
                    adapterType = NetworkAdapterType_Am79C970A;
E
Eric Blake 已提交
4391
                } else if (STRCASEEQ(def->nets[i]->model, "Am79C973")) {
E
Eric Blake 已提交
4392
                    adapterType = NetworkAdapterType_Am79C973;
E
Eric Blake 已提交
4393
                } else if (STRCASEEQ(def->nets[i]->model, "82540EM")) {
E
Eric Blake 已提交
4394
                    adapterType = NetworkAdapterType_I82540EM;
E
Eric Blake 已提交
4395
                } else if (STRCASEEQ(def->nets[i]->model, "82545EM")) {
E
Eric Blake 已提交
4396
                    adapterType = NetworkAdapterType_I82545EM;
E
Eric Blake 已提交
4397
                } else if (STRCASEEQ(def->nets[i]->model, "82543GC")) {
E
Eric Blake 已提交
4398
                    adapterType = NetworkAdapterType_I82543GC;
4399
#if VBOX_API_VERSION >= 3001
E
Eric Blake 已提交
4400
                } else if (STRCASEEQ(def->nets[i]->model, "virtio")) {
E
Eric Blake 已提交
4401
                    adapterType = NetworkAdapterType_Virtio;
4402 4403
#endif /* VBOX_API_VERSION >= 3001 */
                }
E
Eric Blake 已提交
4404 4405 4406
            } else {
                adapterType = NetworkAdapterType_Am79C973;
            }
4407

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

E
Eric Blake 已提交
4410 4411 4412
            if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
                PRUnichar *hostInterface = NULL;
                /* Bridged Network */
4413

4414
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4415
                adapter->vtbl->AttachToBridgedInterface(adapter);
4416 4417 4418
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Bridged);
#endif /* VBOX_API_VERSION >= 4001 */
4419

E
Eric Blake 已提交
4420 4421 4422
                if (def->nets[i]->data.bridge.brname) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.bridge.brname,
                                       &hostInterface);
4423
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4424
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4425 4426 4427
#else /* VBOX_API_VERSION >= 4001 */
                    adapter->vtbl->SetBridgedInterface(adapter, hostInterface);
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4428 4429 4430 4431 4432
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
                PRUnichar *internalNetwork = NULL;
                /* Internal Network */
4433

4434
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4435
                adapter->vtbl->AttachToInternalNetwork(adapter);
4436 4437 4438
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Internal);
#endif /* VBOX_API_VERSION >= 4001 */
4439

E
Eric Blake 已提交
4440 4441 4442 4443 4444
                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);
4445
                }
E
Eric Blake 已提交
4446 4447 4448 4449 4450 4451
            } 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)
                 */
4452
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4453
                adapter->vtbl->AttachToHostOnlyInterface(adapter);
4454 4455 4456
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_HostOnly);
#endif /* VBOX_API_VERSION >= 4001 */
4457

E
Eric Blake 已提交
4458 4459 4460
                if (def->nets[i]->data.network.name) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.network.name,
                                       &hostInterface);
4461
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4462
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4463 4464 4465
#else /* VBOX_API_VERSION >= 4001 */
                    adapter->vtbl->SetHostOnlyInterface(adapter, hostInterface);
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4466 4467 4468 4469
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
                /* NAT */
4470
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4471
                adapter->vtbl->AttachToNAT(adapter);
4472 4473 4474
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4475 4476 4477 4478
            } else {
                /* else always default to NAT if we don't understand
                 * what option is been passed to us
                 */
4479
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4480
                adapter->vtbl->AttachToNAT(adapter);
4481 4482 4483
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
#endif /* VBOX_API_VERSION >= 4001 */
4484
            }
E
Eric Blake 已提交
4485 4486 4487 4488

            VBOX_UTF8_TO_UTF16(macaddrvbox, &MACAddress);
            adapter->vtbl->SetMACAddress(adapter, MACAddress);
            VBOX_UTF16_FREE(MACAddress);
4489
        }
E
Eric Blake 已提交
4490 4491 4492 4493 4494 4495 4496 4497
    }
}

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

E
Eric Blake 已提交
4500 4501 4502 4503 4504 4505 4506
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetSerialPortCount(systemProperties,
                                                   &serialPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4507

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

4513 4514
        VIR_DEBUG("SerialPort(%zu): Type: %d", i, def->serials[i]->source.type);
        VIR_DEBUG("SerialPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4515
              def->serials[i]->target.port);
4516

E
Eric Blake 已提交
4517 4518 4519
        machine->vtbl->GetSerialPort(machine, i, &serialPort);
        if (serialPort) {
            PRUnichar *pathUtf16 = NULL;
4520

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

4523 4524 4525
            if (def->serials[i]->source.data.file.path) {
                VBOX_UTF8_TO_UTF16(def->serials[i]->source.data.file.path,
                                   &pathUtf16);
E
Eric Blake 已提交
4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540
                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);
4541
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4542
                      i, 4, 1016, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4543 4544 4545
            } else if (def->serials[i]->target.port == 1) {
                serialPort->vtbl->SetIRQ(serialPort, 3);
                serialPort->vtbl->SetIOBase(serialPort, 760);
4546
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4547
                      i, 3, 760, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4548
            }
4549

4550
            if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV) {
E
Eric Blake 已提交
4551
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostDevice);
4552
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE) {
E
Eric Blake 已提交
4553
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostPipe);
4554
#if VBOX_API_VERSION >= 3000
4555
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) {
E
Eric Blake 已提交
4556
                serialPort->vtbl->SetHostMode(serialPort, PortMode_RawFile);
4557
#endif /* VBOX_API_VERSION >= 3000 */
E
Eric Blake 已提交
4558 4559 4560 4561
            } else {
                serialPort->vtbl->SetHostMode(serialPort,
                                              PortMode_Disconnected);
            }
4562

E
Eric Blake 已提交
4563
            VBOX_RELEASE(serialPort);
J
John Ferlan 已提交
4564
            VBOX_UTF16_FREE(pathUtf16);
4565
        }
E
Eric Blake 已提交
4566 4567
    }
}
4568

E
Eric Blake 已提交
4569 4570 4571 4572 4573
static void
vboxAttachParallel(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 parallelPortCount          = 0;
4574
    size_t i = 0;
4575

E
Eric Blake 已提交
4576 4577 4578 4579 4580 4581 4582
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetParallelPortCount(systemProperties,
                                                     &parallelPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4583

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

4589 4590
        VIR_DEBUG("ParallelPort(%zu): Type: %d", i, def->parallels[i]->source.type);
        VIR_DEBUG("ParallelPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4591
              def->parallels[i]->target.port);
4592

E
Eric Blake 已提交
4593 4594 4595
        machine->vtbl->GetParallelPort(machine, i, &parallelPort);
        if (parallelPort) {
            PRUnichar *pathUtf16 = NULL;
4596

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

E
Eric Blake 已提交
4599 4600 4601 4602 4603
            /* 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
             */
4604 4605 4606 4607
            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 已提交
4608 4609 4610 4611
                parallelPort->vtbl->SetPath(parallelPort, pathUtf16);
                if (i == 0) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 7);
                    parallelPort->vtbl->SetIOBase(parallelPort, 888);
4612
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4613
                          i, 7, 888, def->parallels[i]->source.data.file.path);
E
Eric Blake 已提交
4614 4615 4616
                } else if (i == 1) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 5);
                    parallelPort->vtbl->SetIOBase(parallelPort, 632);
4617
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4618
                          i, 5, 632, def->parallels[i]->source.data.file.path);
4619 4620
                }
            }
E
Eric Blake 已提交
4621 4622 4623 4624 4625 4626 4627

            /* 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 已提交
4628
            VBOX_UTF16_FREE(pathUtf16);
4629
        }
E
Eric Blake 已提交
4630 4631 4632 4633 4634 4635 4636 4637
    }
}

static void
vboxAttachVideo(virDomainDefPtr def, IMachine *machine)
{
    if ((def->nvideos == 1) &&
        (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_VBOX)) {
4638 4639
        machine->vtbl->SetVRAMSize(machine,
                                   VIR_DIV_UP(def->videos[0]->vram, 1024));
E
Eric Blake 已提交
4640 4641 4642 4643
        machine->vtbl->SetMonitorCount(machine, def->videos[0]->heads);
        if (def->videos[0]->accel) {
            machine->vtbl->SetAccelerate3DEnabled(machine,
                                                  def->videos[0]->accel->support3d);
4644
#if VBOX_API_VERSION >= 3001
E
Eric Blake 已提交
4645 4646
            machine->vtbl->SetAccelerate2DVideoEnabled(machine,
                                                       def->videos[0]->accel->support2d);
4647
#endif /* VBOX_API_VERSION >= 3001 */
E
Eric Blake 已提交
4648 4649
        } else {
            machine->vtbl->SetAccelerate3DEnabled(machine, 0);
4650
#if VBOX_API_VERSION >= 3001
E
Eric Blake 已提交
4651
            machine->vtbl->SetAccelerate2DVideoEnabled(machine, 0);
4652 4653
#endif /* VBOX_API_VERSION >= 3001 */
        }
E
Eric Blake 已提交
4654 4655
    }
}
4656

E
Eric Blake 已提交
4657 4658 4659 4660 4661 4662 4663 4664
static void
vboxAttachDisplay(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    int vrdpPresent  = 0;
    int sdlPresent   = 0;
    int guiPresent   = 0;
    char *guiDisplay = NULL;
    char *sdlDisplay = NULL;
4665
    size_t i = 0;
4666

E
Eric Blake 已提交
4667
    for (i = 0; i < def->ngraphics; i++) {
4668 4669 4670 4671 4672
#if VBOX_API_VERSION < 4000
        IVRDPServer *VRDxServer = NULL;
#else /* VBOX_API_VERSION >= 4000 */
        IVRDEServer *VRDxServer = NULL;
#endif /* VBOX_API_VERSION >= 4000 */
4673

E
Eric Blake 已提交
4674 4675
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) &&
            (vrdpPresent == 0)) {
4676

E
Eric Blake 已提交
4677
            vrdpPresent = 1;
4678 4679 4680 4681 4682 4683
#if VBOX_API_VERSION < 4000
            machine->vtbl->GetVRDPServer(machine, &VRDxServer);
#else /* VBOX_API_VERSION >= 4000 */
            machine->vtbl->GetVRDEServer(machine, &VRDxServer);
#endif /* VBOX_API_VERSION >= 4000 */
            if (VRDxServer) {
4684 4685 4686
                const char *listenAddr
                    = virDomainGraphicsListenGetAddress(def->graphics[i], 0);

4687
                VRDxServer->vtbl->SetEnabled(VRDxServer, PR_TRUE);
4688
                VIR_DEBUG("VRDP Support turned ON.");
4689 4690

#if VBOX_API_VERSION < 3001
E
Eric Blake 已提交
4691
                if (def->graphics[i]->data.rdp.port) {
4692
                    VRDxServer->vtbl->SetPort(VRDxServer,
E
Eric Blake 已提交
4693
                                              def->graphics[i]->data.rdp.port);
4694
                    VIR_DEBUG("VRDP Port changed to: %d",
E
Eric Blake 已提交
4695 4696 4697 4698 4699
                          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
                     */
4700
                    VRDxServer->vtbl->SetPort(VRDxServer, 0);
4701
                    VIR_DEBUG("VRDP Port changed to default, which is 3389 currently");
E
Eric Blake 已提交
4702
                }
4703
#elif VBOX_API_VERSION < 4000 /* 3001 <= VBOX_API_VERSION < 4000 */
E
Eric Blake 已提交
4704 4705
                PRUnichar *portUtf16 = NULL;
                portUtf16 = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
4706
                VRDxServer->vtbl->SetPorts(VRDxServer, portUtf16);
E
Eric Blake 已提交
4707
                VBOX_UTF16_FREE(portUtf16);
4708 4709 4710 4711 4712 4713 4714 4715 4716 4717
#else /* VBOX_API_VERSION >= 4000 */
                PRUnichar *VRDEPortsKey = NULL;
                PRUnichar *VRDEPortsValue = NULL;
                VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey);
                VRDEPortsValue = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
                VRDxServer->vtbl->SetVRDEProperty(VRDxServer, VRDEPortsKey,
                                                  VRDEPortsValue);
                VBOX_UTF16_FREE(VRDEPortsKey);
                VBOX_UTF16_FREE(VRDEPortsValue);
#endif /* VBOX_API_VERSION >= 4000 */
4718

E
Eric Blake 已提交
4719
                if (def->graphics[i]->data.rdp.replaceUser) {
4720
                    VRDxServer->vtbl->SetReuseSingleConnection(VRDxServer,
E
Eric Blake 已提交
4721
                                                               PR_TRUE);
4722
                    VIR_DEBUG("VRDP set to reuse single connection");
E
Eric Blake 已提交
4723
                }
4724

E
Eric Blake 已提交
4725
                if (def->graphics[i]->data.rdp.multiUser) {
4726
                    VRDxServer->vtbl->SetAllowMultiConnection(VRDxServer,
E
Eric Blake 已提交
4727
                                                              PR_TRUE);
4728
                    VIR_DEBUG("VRDP set to allow multiple connection");
E
Eric Blake 已提交
4729
                }
4730

4731
                if (listenAddr) {
4732 4733 4734
#if VBOX_API_VERSION >= 4000
                    PRUnichar *netAddressKey = NULL;
#endif
E
Eric Blake 已提交
4735
                    PRUnichar *netAddressUtf16 = NULL;
4736

4737
                    VBOX_UTF8_TO_UTF16(listenAddr, &netAddressUtf16);
4738 4739
#if VBOX_API_VERSION < 4000
                    VRDxServer->vtbl->SetNetAddress(VRDxServer,
E
Eric Blake 已提交
4740
                                                    netAddressUtf16);
4741 4742 4743 4744 4745 4746
#else /* VBOX_API_VERSION >= 4000 */
                    VBOX_UTF8_TO_UTF16("TCP/Address", &netAddressKey);
                    VRDxServer->vtbl->SetVRDEProperty(VRDxServer, netAddressKey,
                                                      netAddressUtf16);
                    VBOX_UTF16_FREE(netAddressKey);
#endif /* VBOX_API_VERSION >= 4000 */
4747
                    VIR_DEBUG("VRDP listen address is set to: %s",
4748
                              listenAddr);
4749

E
Eric Blake 已提交
4750
                    VBOX_UTF16_FREE(netAddressUtf16);
4751
                }
E
Eric Blake 已提交
4752

4753
                VBOX_RELEASE(VRDxServer);
4754
            }
E
Eric Blake 已提交
4755
        }
4756

E
Eric Blake 已提交
4757 4758 4759
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) &&
            (guiPresent == 0)) {
            guiPresent = 1;
4760 4761 4762 4763 4764
            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
                 */
4765
            }
E
Eric Blake 已提交
4766
        }
4767

E
Eric Blake 已提交
4768 4769 4770
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) &&
            (sdlPresent == 0)) {
            sdlPresent = 1;
4771 4772 4773 4774 4775
            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
                 */
4776
            }
4777
        }
E
Eric Blake 已提交
4778
    }
4779

E
Eric Blake 已提交
4780 4781 4782 4783
    if ((vrdpPresent == 1) && (guiPresent == 0) && (sdlPresent == 0)) {
        /* store extradata key that frontend is set to vrdp */
        PRUnichar *keyTypeUtf16   = NULL;
        PRUnichar *valueTypeUtf16 = NULL;
4784

E
Eric Blake 已提交
4785 4786
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("vrdp", &valueTypeUtf16);
4787

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

E
Eric Blake 已提交
4790 4791
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4792

E
Eric Blake 已提交
4793 4794 4795 4796 4797 4798
    } 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;
4799

E
Eric Blake 已提交
4800 4801
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("sdl", &valueTypeUtf16);
4802

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

E
Eric Blake 已提交
4805 4806
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4807

E
Eric Blake 已提交
4808 4809 4810
        if (sdlDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(sdlDisplay, &valueDisplayUtf16);
4811

E
Eric Blake 已提交
4812 4813
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4814

E
Eric Blake 已提交
4815 4816 4817
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
        }
4818

E
Eric Blake 已提交
4819 4820 4821 4822 4823 4824
    } 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;
4825

E
Eric Blake 已提交
4826 4827
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("gui", &valueTypeUtf16);
4828

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

E
Eric Blake 已提交
4831 4832
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4833

E
Eric Blake 已提交
4834 4835 4836
        if (guiDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(guiDisplay, &valueDisplayUtf16);
4837

E
Eric Blake 已提交
4838 4839
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4840

E
Eric Blake 已提交
4841 4842
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
4843
        }
E
Eric Blake 已提交
4844
    }
4845

E
Eric Blake 已提交
4846 4847 4848
    VIR_FREE(guiDisplay);
    VIR_FREE(sdlDisplay);
}
4849

E
Eric Blake 已提交
4850 4851 4852 4853
static void
vboxAttachUSB(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    IUSBController *USBController = NULL;
4854
    size_t i = 0;
E
Eric Blake 已提交
4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865
    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 已提交
4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881
        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 已提交
4882 4883
    }

R
Ryota Ozaki 已提交
4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895
    if (!isUSB)
        return;

    /* 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);
4896
#if VBOX_API_VERSION < 4002
R
Ryota Ozaki 已提交
4897
    USBController->vtbl->SetEnabledEhci(USBController, 1);
4898
#else
R
Ryota Ozaki 已提交
4899
    USBController->vtbl->SetEnabledEHCI(USBController, 1);
4900
#endif
4901

R
Ryota Ozaki 已提交
4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912
    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;
4913

R
Ryota Ozaki 已提交
4914 4915 4916
        if (def->hostdevs[i]->source.subsys.type !=
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;
4917

R
Ryota Ozaki 已提交
4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928
        /* 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);
            USBController->vtbl->CreateDeviceFilter(USBController,
                                                    filternameUtf16,
                                                    &filter);
        }
        VBOX_UTF16_FREE(filternameUtf16);
E
Eric Blake 已提交
4929

R
Ryota Ozaki 已提交
4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950
        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 已提交
4951
        }
R
Ryota Ozaki 已提交
4952 4953 4954 4955 4956
        filter->vtbl->SetActive(filter, 1);
        USBController->vtbl->InsertDeviceFilter(USBController,
                                                i,
                                                filter);
        VBOX_RELEASE(filter);
E
Eric Blake 已提交
4957
    }
R
Ryota Ozaki 已提交
4958
    VBOX_RELEASE(USBController);
E
Eric Blake 已提交
4959 4960
}

M
Matthias Bolte 已提交
4961 4962 4963
static void
vboxAttachSharedFolder(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
4964
    size_t i;
M
Matthias Bolte 已提交
4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992
    PRUnichar *nameUtf16;
    PRUnichar *hostPathUtf16;
    PRBool writable;

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

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

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

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

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

E
Eric Blake 已提交
4993 4994 4995 4996
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml) {
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
    IMachine       *machine     = NULL;
    IBIOSSettings  *bios        = NULL;
4997 4998
    vboxIID iid = VBOX_IID_INITIALIZER;
    vboxIID mchiid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
4999 5000
    virDomainDefPtr def         = NULL;
    PRUnichar *machineNameUtf16 = NULL;
5001
#if VBOX_API_VERSION >= 3002 && VBOX_API_VERSION < 4002
E
Eric Blake 已提交
5002 5003 5004
    PRBool override             = PR_FALSE;
#endif
    nsresult rc;
5005 5006 5007 5008 5009 5010 5011 5012
    char uuidstr[VIR_UUID_STRING_BUFLEN];
#if VBOX_API_VERSION >= 4002
    const char *flagsUUIDPrefix = "UUID=";
    const char *flagsForceOverwrite = "forceOverwrite=0";
    const char *flagsSeparator = ",";
    char createFlags[strlen(flagsUUIDPrefix) + VIR_UUID_STRING_BUFLEN + strlen(flagsSeparator) + strlen(flagsForceOverwrite) + 1];
    PRUnichar *createFlagsUtf16 = NULL;
#endif
E
Eric Blake 已提交
5013

5014 5015
    if (!(def = virDomainDefParseString(xml, data->caps, data->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_VBOX,
E
Eric Blake 已提交
5016 5017 5018 5019 5020
                                        VIR_DOMAIN_XML_INACTIVE))) {
        goto cleanup;
    }

    VBOX_UTF8_TO_UTF16(def->name, &machineNameUtf16);
5021
    vboxIIDFromUUID(&iid, def->uuid);
5022 5023
    virUUIDFormat(def->uuid, uuidstr);

E
Eric Blake 已提交
5024 5025 5026 5027 5028
#if VBOX_API_VERSION < 3002
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
5029
                                            iid.value,
E
Eric Blake 已提交
5030
                                            &machine);
5031
#elif VBOX_API_VERSION < 4000 /* 3002 <= VBOX_API_VERSION < 4000 */
E
Eric Blake 已提交
5032 5033 5034 5035
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
5036
                                            iid.value,
E
Eric Blake 已提交
5037 5038
                                            override,
                                            &machine);
5039
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
5040 5041 5042 5043 5044 5045 5046
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            NULL,
                                            machineNameUtf16,
                                            NULL,
                                            iid.value,
                                            override,
                                            &machine);
5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063
#else /* VBOX_API_VERSION >= 4002 */
    snprintf(createFlags, sizeof(createFlags), "%s%s%s%s",
             flagsUUIDPrefix,
             uuidstr,
             flagsSeparator,
             flagsForceOverwrite
            );
    VBOX_UTF8_TO_UTF16(createFlags, &createFlagsUtf16);
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            NULL,
                                            machineNameUtf16,
                                            0,
                                            nsnull,
                                            nsnull,
                                            createFlagsUtf16,
                                            &machine);
#endif /* VBOX_API_VERSION >= 4002 */
E
Eric Blake 已提交
5064 5065 5066
    VBOX_UTF16_FREE(machineNameUtf16);

    if (NS_FAILED(rc)) {
5067 5068
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
5069 5070 5071
        goto cleanup;
    }

5072 5073
    rc = machine->vtbl->SetMemorySize(machine,
                                      VIR_DIV_UP(def->mem.cur_balloon, 1024));
E
Eric Blake 已提交
5074
    if (NS_FAILED(rc)) {
5075 5076 5077 5078
        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 已提交
5079 5080
    }

E
Eric Blake 已提交
5081
    if (def->vcpus != def->maxvcpus) {
5082 5083
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("current vcpu count must equal maximum"));
E
Eric Blake 已提交
5084 5085
    }
    rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus);
E
Eric Blake 已提交
5086
    if (NS_FAILED(rc)) {
5087 5088 5089
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not set the number of virtual CPUs to: %u, rc=%08x"),
                       def->maxvcpus, (unsigned)rc);
E
Eric Blake 已提交
5090 5091 5092
    }

#if VBOX_API_VERSION < 3001
5093 5094 5095
    rc = machine->vtbl->SetPAEEnabled(machine,
                                      def->features[VIR_DOMAIN_FEATURE_PAE] ==
                                      VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5096 5097
#elif VBOX_API_VERSION == 3001
    rc = machine->vtbl->SetCpuProperty(machine, CpuPropertyType_PAE,
5098 5099
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
                                       VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5100 5101
#elif VBOX_API_VERSION >= 3002
    rc = machine->vtbl->SetCPUProperty(machine, CPUPropertyType_PAE,
5102 5103
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
                                       VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5104 5105
#endif
    if (NS_FAILED(rc)) {
5106 5107
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not change PAE status to: %s, rc=%08x"),
5108
                       (def->features[VIR_DOMAIN_FEATURE_PAE] == VIR_DOMAIN_FEATURE_STATE_ON)
5109
                       ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
5110 5111 5112 5113
    }

    machine->vtbl->GetBIOSSettings(machine, &bios);
    if (bios) {
5114 5115 5116
        rc = bios->vtbl->SetACPIEnabled(bios,
                                        def->features[VIR_DOMAIN_FEATURE_ACPI] ==
                                        VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5117
        if (NS_FAILED(rc)) {
5118 5119
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change ACPI status to: %s, rc=%08x"),
5120
                           (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_DOMAIN_FEATURE_STATE_ON)
5121
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
5122
        }
5123 5124 5125
        rc = bios->vtbl->SetIOAPICEnabled(bios,
                                          def->features[VIR_DOMAIN_FEATURE_APIC] ==
                                          VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5126
        if (NS_FAILED(rc)) {
5127 5128
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change APIC status to: %s, rc=%08x"),
5129
                           (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_DOMAIN_FEATURE_STATE_ON)
5130
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
5131
        }
E
Eric Blake 已提交
5132 5133 5134 5135 5136 5137
        VBOX_RELEASE(bios);
    }

    /* Register the machine before attaching other devices to it */
    rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
    if (NS_FAILED(rc)) {
5138 5139
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
5140 5141 5142 5143 5144 5145 5146
        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
     */
5147
    machine->vtbl->GetId(machine, &mchiid.value);
5148
    VBOX_SESSION_OPEN(mchiid.value, machine);
E
Eric Blake 已提交
5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159
    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 已提交
5160
    vboxAttachSharedFolder(def, data, machine);
5161

5162 5163 5164 5165
    /* Save the machine settings made till now and close the
     * session. also free up the mchiid variable used.
     */
    rc = machine->vtbl->SaveSettings(machine);
5166
    VBOX_SESSION_CLOSE();
5167
    vboxIIDUnalloc(&mchiid);
5168

5169 5170
    ret = virGetDomain(conn, def->name, def->uuid);
    VBOX_RELEASE(machine);
5171

5172
    vboxIIDUnalloc(&iid);
5173 5174
    virDomainDefFree(def);

5175
    return ret;
5176 5177

cleanup:
5178
    VBOX_RELEASE(machine);
5179
    vboxIIDUnalloc(&iid);
5180 5181 5182 5183
    virDomainDefFree(def);
    return NULL;
}

5184
static int
5185
vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags)
5186
{
5187
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5188
    IMachine *machine    = NULL;
5189
    vboxIID iid = VBOX_IID_INITIALIZER;
5190
    nsresult rc;
5191 5192 5193
#if VBOX_API_VERSION >= 4000
    vboxArray media = VBOX_ARRAY_INITIALIZER;
#endif
5194 5195 5196 5197
    /* 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);
5198

5199
    vboxIIDFromUUID(&iid, dom->uuid);
5200

5201
#if VBOX_API_VERSION < 4000
5202 5203 5204
    /* 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
5205 5206 5207 5208
     * 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.
5209 5210 5211
     */
    {
        PRUnichar *hddcnameUtf16 = NULL;
5212

5213 5214
        char *hddcname;
        ignore_value(VIR_STRDUP(hddcname, "IDE"));
5215 5216
        VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
        VIR_FREE(hddcname);
5217

5218
        /* Open a Session for the machine */
5219
        rc = VBOX_SESSION_OPEN(iid.value, machine);
5220 5221 5222 5223
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {

5224
# if VBOX_API_VERSION < 3001
5225 5226 5227 5228
                /* 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);
5229
# else  /* VBOX_API_VERSION >= 3001 */
5230 5231 5232
                /* get all the controller first, then the attachments and
                 * remove them all so that the machine can be undefined
                 */
5233
                vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
5234
                size_t i = 0, j = 0;
5235

5236 5237
                vboxArrayGet(&storageControllers, machine,
                             machine->vtbl->GetStorageControllers);
5238

5239 5240
                for (i = 0; i < storageControllers.count; i++) {
                    IStorageController *strCtl = storageControllers.items[i];
5241
                    PRUnichar *strCtlName = NULL;
5242
                    vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
5243 5244 5245 5246 5247

                    if (!strCtl)
                        continue;

                    strCtl->vtbl->GetName(strCtl, &strCtlName);
5248 5249 5250
                    vboxArrayGetWithPtrArg(&mediumAttachments, machine,
                                           machine->vtbl->GetMediumAttachmentsOfController,
                                           strCtlName);
5251

5252 5253
                    for (j = 0; j < mediumAttachments.count; j++) {
                        IMediumAttachment *medAtt = mediumAttachments.items[j];
5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269
                        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);
                        }
                    }
5270

5271 5272
                    vboxArrayRelease(&storageControllers);

5273 5274
                    machine->vtbl->RemoveStorageController(machine, strCtlName);
                    VBOX_UTF16_FREE(strCtlName);
5275
                }
5276 5277

                vboxArrayRelease(&storageControllers);
5278
# endif /* VBOX_API_VERSION >= 3001 */
5279 5280

                machine->vtbl->SaveSettings(machine);
5281
            }
5282
            VBOX_SESSION_CLOSE();
5283
        }
5284 5285
        VBOX_UTF16_FREE(hddcnameUtf16);
    }
5286
#endif
5287

5288
#if VBOX_API_VERSION < 4000
5289
    rc = data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, iid.value, &machine);
5290 5291 5292
#else /* VBOX_API_VERSION >= 4000 */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
5293 5294
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5295 5296 5297 5298 5299 5300 5301 5302 5303 5304
        return -1;
    }

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

5307 5308
    if (NS_SUCCEEDED(rc)) {
#if VBOX_API_VERSION < 4000
5309
        machine->vtbl->DeleteSettings(machine);
5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325
#else /* VBOX_API_VERSION >= 4000 */
        IProgress *progress = NULL;

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

        ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress);
# else
5326 5327 5328 5329
        /* XPCOM doesn't like NULL as an array, even when the array size is 0.
         * Instead pass it a dummy array to avoid passing NULL. */
        IMedium *array[] = { NULL };
        machine->vtbl->Delete(machine, 0, array, &progress);
5330 5331 5332 5333 5334 5335
# endif
        if (progress != NULL) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
#endif /* VBOX_API_VERSION >= 4000 */
5336 5337
        ret = 0;
    } else {
5338 5339
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not delete the domain, rc=%08x"), (unsigned)rc);
5340 5341
    }

5342 5343 5344
#if VBOX_API_VERSION >= 4000
    vboxArrayUnalloc(&media);
#endif
5345
    vboxIIDUnalloc(&iid);
5346
    VBOX_RELEASE(machine);
5347 5348 5349 5350

    return ret;
}

5351 5352 5353 5354 5355 5356
static int
vboxDomainUndefine(virDomainPtr dom)
{
    return vboxDomainUndefineFlags(dom, 0);
}

5357 5358 5359
static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
                                      const char *xml,
                                      int mediaChangeOnly ATTRIBUTE_UNUSED) {
5360
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5361
    IMachine *machine    = NULL;
5362
    vboxIID iid = VBOX_IID_INITIALIZER;
5363 5364 5365
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5366
    nsresult rc;
5367

5368
    if (VIR_ALLOC(def) < 0)
5369 5370
        return ret;

5371
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5372 5373
        goto cleanup;

5374 5375
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5376
    if (dev == NULL)
5377 5378
        goto cleanup;

5379
    vboxIIDFromUUID(&iid, dom->uuid);
5380
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5381
    if (NS_FAILED(rc)) {
5382 5383
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5384 5385
        goto cleanup;
    }
5386

5387 5388
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5389

5390 5391
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5392
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5393
        } else {
5394
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5395 5396 5397 5398 5399 5400 5401
        }
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
#if VBOX_API_VERSION < 3001
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
5402 5403
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                            dev->data.disk->src != NULL) {
5404 5405 5406 5407 5408 5409 5410 5411 5412
                            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;
5413 5414
                                vboxIID dvduuid = VBOX_IID_INITIALIZER;
                                vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
5415

5416
                                VBOX_UTF8_TO_UTF16(dev->data.disk->src, &dvdfileUtf16);
5417

5418 5419
                                data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                if (!dvdImage) {
5420
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage);
5421 5422
                                }
                                if (dvdImage) {
5423
                                    rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value);
5424
                                    if (NS_FAILED(rc)) {
5425 5426 5427 5428
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("can't get the uuid of the file to "
                                                         "be attached to cdrom: %s, rc=%08x"),
                                                       dev->data.disk->src, (unsigned)rc);
5429 5430 5431
                                    } else {
                                        /* unmount the previous mounted image */
                                        dvdDrive->vtbl->Unmount(dvdDrive);
5432
                                        rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
5433
                                        if (NS_FAILED(rc)) {
5434 5435 5436
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("could not attach the file to cdrom: %s, rc=%08x"),
                                                           dev->data.disk->src, (unsigned)rc);
5437
                                        } else {
5438
                                            ret = 0;
5439
                                            DEBUGIID("CD/DVD Image UUID:", dvduuid.value);
5440 5441
                                        }
                                    }
5442 5443

                                    VBOX_MEDIUM_RELEASE(dvdImage);
5444
                                }
5445
                                vboxIIDUnalloc(&dvduuid);
5446 5447
                                VBOX_UTF16_FREE(dvdfileUtf16);
                                VBOX_RELEASE(dvdDrive);
5448
                            }
5449 5450 5451
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
5452 5453
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                            dev->data.disk->src != NULL) {
5454 5455 5456 5457 5458 5459 5460
                            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;
5461 5462
                                    vboxIID fduuid = VBOX_IID_INITIALIZER;
                                    vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
5463 5464 5465 5466 5467 5468 5469 5470
                                    VBOX_UTF8_TO_UTF16(dev->data.disk->src, &fdfileUtf16);
                                    rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                              fdfileUtf16,
                                                                              &floppyImage);

                                    if (!floppyImage) {
                                        data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                             fdfileUtf16,
5471
                                                                             fdemptyuuid.value,
5472 5473
                                                                             &floppyImage);
                                    }
5474

5475
                                    if (floppyImage) {
5476
                                        rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value);
5477
                                        if (NS_FAILED(rc)) {
5478 5479 5480 5481
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("can't get the uuid of the file to be "
                                                             "attached to floppy drive: %s, rc=%08x"),
                                                           dev->data.disk->src, (unsigned)rc);
5482
                                        } else {
5483
                                            rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value);
5484
                                            if (NS_FAILED(rc)) {
5485 5486 5487
                                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                                               _("could not attach the file to floppy drive: %s, rc=%08x"),
                                                               dev->data.disk->src, (unsigned)rc);
5488
                                            } else {
5489
                                                ret = 0;
5490
                                                DEBUGIID("attached floppy, UUID:", fduuid.value);
5491 5492
                                            }
                                        }
5493
                                        VBOX_MEDIUM_RELEASE(floppyImage);
5494
                                    }
5495
                                    vboxIIDUnalloc(&fduuid);
5496
                                    VBOX_UTF16_FREE(fdfileUtf16);
5497
                                }
5498
                                VBOX_RELEASE(floppyDrive);
5499
                            }
5500
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5501
                        }
5502 5503 5504 5505 5506 5507 5508
                    }
#else  /* VBOX_API_VERSION >= 3001 */
#endif /* VBOX_API_VERSION >= 3001 */
                } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
                } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
                    if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                        if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
5509 5510
                        }
                    }
M
Matthias Bolte 已提交
5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529
                } else if (dev->type == VIR_DOMAIN_DEVICE_FS &&
                           dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
                    PRUnichar *nameUtf16;
                    PRUnichar *hostPathUtf16;
                    PRBool writable;

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

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

                    if (NS_FAILED(rc)) {
5530 5531 5532
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not attach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5533 5534 5535 5536 5537 5538
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
                    VBOX_UTF16_FREE(hostPathUtf16);
5539
                }
5540 5541
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5542
            }
5543
            VBOX_SESSION_CLOSE();
5544 5545 5546 5547
        }
    }

cleanup:
5548
    vboxIIDUnalloc(&iid);
5549 5550 5551 5552 5553
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5554 5555 5556 5557
static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml) {
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

5558 5559 5560 5561 5562 5563
static int
vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5564
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5565 5566
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5567 5568 5569
        return -1;
    }

5570 5571 5572 5573 5574
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags) {
5575 5576 5577
    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
                  VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
5578

5579
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5580 5581
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5582 5583 5584 5585
        return -1;
    }

    return vboxDomainAttachDeviceImpl(dom, xml, 1);
5586 5587
}

5588
static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml) {
5589
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5590
    IMachine *machine    = NULL;
5591
    vboxIID iid = VBOX_IID_INITIALIZER;
5592 5593 5594
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5595
    nsresult rc;
5596

5597
    if (VIR_ALLOC(def) < 0)
5598 5599
        return ret;

5600
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5601 5602
        goto cleanup;

5603 5604
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5605
    if (dev == NULL)
5606 5607
        goto cleanup;

5608
    vboxIIDFromUUID(&iid, dom->uuid);
5609
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5610
    if (NS_FAILED(rc)) {
5611 5612
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5613 5614
        goto cleanup;
    }
5615

5616 5617
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5618

5619 5620
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5621
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5622
        } else {
5623
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5624
        }
5625

5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
#if VBOX_API_VERSION < 3001
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                            IDVDDrive *dvdDrive = NULL;
                            /* Currently CDROM/DVD Drive is always IDE
                             * Secondary Master so neglecting the following
                             * parameter dev->data.disk->bus
                             */
                            machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                            if (dvdDrive) {
                                rc = dvdDrive->vtbl->Unmount(dvdDrive);
                                if (NS_FAILED(rc)) {
5642 5643 5644
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not de-attach the mounted ISO, rc=%08x"),
                                                   (unsigned)rc);
5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661
                                } else {
                                    ret = 0;
                                }
                                VBOX_RELEASE(dvdDrive);
                            }
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                            IFloppyDrive *floppyDrive;
                            machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                            if (floppyDrive) {
                                PRBool enabled = PR_FALSE;

                                floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
                                if (enabled) {
                                    rc = floppyDrive->vtbl->Unmount(floppyDrive);
5662
                                    if (NS_FAILED(rc)) {
5663 5664 5665 5666
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("could not attach the file "
                                                         "to floppy drive, rc=%08x"),
                                                       (unsigned)rc);
5667 5668 5669
                                    } else {
                                        ret = 0;
                                    }
5670 5671 5672 5673 5674
                                } 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;
5675
                                }
5676
                                VBOX_RELEASE(floppyDrive);
5677
                            }
5678
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5679
                        }
5680 5681 5682 5683 5684 5685 5686
                    }
#else  /* VBOX_API_VERSION >= 3001 */
#endif /* VBOX_API_VERSION >= 3001 */
                } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
                } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
                    if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                        if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
5687 5688
                        }
                    }
M
Matthias Bolte 已提交
5689 5690 5691 5692 5693 5694 5695 5696 5697
                } 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)) {
5698 5699 5700
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not detach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5701 5702 5703 5704 5705
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
5706
                }
5707 5708
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5709
            }
5710
            VBOX_SESSION_CLOSE();
5711 5712 5713 5714
        }
    }

cleanup:
5715
    vboxIIDUnalloc(&iid);
5716 5717 5718 5719 5720
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5721 5722 5723 5724 5725 5726
static int
vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5727
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5728 5729
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5730 5731 5732 5733 5734 5735
        return -1;
    }

    return vboxDomainDetachDevice(dom, xml);
}

J
Jiri Denemark 已提交
5736 5737 5738 5739 5740
static int
vboxDomainSnapshotGetAll(virDomainPtr dom,
                         IMachine *machine,
                         ISnapshot ***snapshots)
{
5741
    vboxIID empty = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5742 5743 5744 5745 5746 5747 5748 5749
    ISnapshot **list = NULL;
    PRUint32 count;
    nsresult rc;
    unsigned int next;
    unsigned int top;

    rc = machine->vtbl->GetSnapshotCount(machine, &count);
    if (NS_FAILED(rc)) {
5750 5751 5752
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5753 5754 5755 5756 5757 5758
        goto error;
    }

    if (count == 0)
        goto out;

5759
    if (VIR_ALLOC_N(list, count) < 0)
J
Jiri Denemark 已提交
5760 5761
        goto error;

5762
#if VBOX_API_VERSION < 4000
5763
    rc = machine->vtbl->GetSnapshot(machine, empty.value, list);
5764 5765 5766
#else /* VBOX_API_VERSION >= 4000 */
    rc = machine->vtbl->FindSnapshot(machine, empty.value, list);
#endif /* VBOX_API_VERSION >= 4000 */
J
Jiri Denemark 已提交
5767
    if (NS_FAILED(rc) || !list[0]) {
5768 5769 5770
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get root snapshot for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5771 5772 5773 5774 5775 5776
        goto error;
    }

    /* BFS walk through snapshot tree */
    top = 1;
    for (next = 0; next < count; next++) {
5777
        vboxArray children = VBOX_ARRAY_INITIALIZER;
5778
        size_t i;
J
Jiri Denemark 已提交
5779 5780

        if (!list[next]) {
5781 5782
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected number of snapshots < %u"), count);
J
Jiri Denemark 已提交
5783 5784 5785
            goto error;
        }

5786 5787
        rc = vboxArrayGet(&children, list[next],
                               list[next]->vtbl->GetChildren);
J
Jiri Denemark 已提交
5788
        if (NS_FAILED(rc)) {
5789 5790
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get children snapshots"));
J
Jiri Denemark 已提交
5791 5792
            goto error;
        }
5793 5794 5795
        for (i = 0; i < children.count; i++) {
            ISnapshot *child = children.items[i];
            if (!child)
J
Jiri Denemark 已提交
5796 5797
                continue;
            if (top == count) {
5798 5799
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected number of snapshots > %u"), count);
5800
                vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5801 5802
                goto error;
            }
5803 5804
            VBOX_ADDREF(child);
            list[top++] = child;
J
Jiri Denemark 已提交
5805
        }
5806
        vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832
    }

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;
5833
    size_t i;
J
Jiri Denemark 已提交
5834 5835 5836 5837 5838 5839 5840 5841 5842 5843

    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) {
5844 5845
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858
            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) {
5859 5860 5861
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s has no snapshots with name %s"),
                       dom->name, name);
J
Jiri Denemark 已提交
5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878
        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,
5879
                            unsigned int flags)
J
Jiri Denemark 已提交
5880 5881 5882
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    virDomainSnapshotDefPtr def = NULL;
5883
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897
    IMachine *machine = NULL;
    IConsole *console = NULL;
    IProgress *progress = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *name = NULL;
    PRUnichar *description = NULL;
    PRUint32 state;
    nsresult rc;
#if VBOX_API_VERSION == 2002
    nsresult result;
#else
    PRInt32 result;
#endif

5898 5899
    /* VBox has no snapshot metadata, so this flag is trivial.  */
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
5900

5901
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
5902
                                                data->xmlopt, 0, 0)))
J
Jiri Denemark 已提交
5903 5904
        goto cleanup;

5905
    if (def->ndisks) {
5906 5907
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk snapshots not supported yet"));
5908 5909 5910
        goto cleanup;
    }

5911
    vboxIIDFromUUID(&domiid, dom->uuid);
5912
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
5913
    if (NS_FAILED(rc)) {
5914 5915
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5916 5917 5918 5919 5920
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
5921 5922
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
5923 5924 5925 5926 5927
        goto cleanup;
    }

    if ((state >= MachineState_FirstOnline)
        && (state <= MachineState_LastOnline)) {
5928
        rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine);
J
Jiri Denemark 已提交
5929
    } else {
5930
        rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
5931
    }
5932

J
Jiri Denemark 已提交
5933 5934 5935
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
5936 5937 5938
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957
        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) {
5958 5959
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
5960 5961 5962 5963 5964 5965
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
5966 5967
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
5968 5969 5970 5971 5972
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
5973 5974
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
J
Jiri Denemark 已提交
5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985
                  dom->name);
        goto cleanup;
    }

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

cleanup:
    VBOX_RELEASE(progress);
    VBOX_UTF16_FREE(description);
    VBOX_UTF16_FREE(name);
    VBOX_RELEASE(console);
5986
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
5987
    VBOX_RELEASE(machine);
5988
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
5989 5990 5991 5992 5993
    virDomainSnapshotDefFree(def);
    return ret;
}

static char *
5994 5995
vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                             unsigned int flags)
J
Jiri Denemark 已提交
5996 5997 5998
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
5999
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010
    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];

6011 6012
    virCheckFlags(0, NULL);

6013
    vboxIIDFromUUID(&domiid, dom->uuid);
6014
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6015
    if (NS_FAILED(rc)) {
6016 6017
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6018 6019 6020 6021 6022 6023
        goto cleanup;
    }

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

6024
    if (VIR_ALLOC(def) < 0)
6025
        goto cleanup;
6026 6027
    if (VIR_STRDUP(def->name, snapshot->name) < 0)
        goto cleanup;
J
Jiri Denemark 已提交
6028 6029 6030

    rc = snap->vtbl->GetDescription(snap, &str16);
    if (NS_FAILED(rc)) {
6031 6032 6033
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get description of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6034 6035 6036 6037 6038
        goto cleanup;
    }
    if (str16) {
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
6039 6040 6041 6042
        if (VIR_STRDUP(def->description, str8) < 0) {
            VBOX_UTF8_FREE(str8);
            goto cleanup;
        }
J
Jiri Denemark 已提交
6043 6044 6045 6046 6047
        VBOX_UTF8_FREE(str8);
    }

    rc = snap->vtbl->GetTimeStamp(snap, &timestamp);
    if (NS_FAILED(rc)) {
6048 6049 6050
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get creation time of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6051 6052 6053 6054 6055 6056 6057
        goto cleanup;
    }
    /* timestamp is in milliseconds while creationTime in seconds */
    def->creationTime = timestamp / 1000;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
6058 6059 6060
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6061 6062 6063 6064 6065
        goto cleanup;
    }
    if (parent) {
        rc = parent->vtbl->GetName(parent, &str16);
        if (NS_FAILED(rc) || !str16) {
6066 6067 6068
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get name of parent of snapshot %s"),
                           snapshot->name);
J
Jiri Denemark 已提交
6069 6070 6071 6072
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
6073 6074
        if (VIR_STRDUP(def->parent, str8) < 0) {
            VBOX_UTF8_FREE(str8);
6075
            goto cleanup;
6076 6077
        }
        VBOX_UTF8_FREE(str8);
J
Jiri Denemark 已提交
6078 6079 6080 6081
    }

    rc = snap->vtbl->GetOnline(snap, &online);
    if (NS_FAILED(rc)) {
6082 6083 6084
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6085 6086 6087 6088 6089 6090 6091 6092
        goto cleanup;
    }
    if (online)
        def->state = VIR_DOMAIN_RUNNING;
    else
        def->state = VIR_DOMAIN_SHUTOFF;

    virUUIDFormat(dom->uuid, uuidstr);
6093
    ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0);
J
Jiri Denemark 已提交
6094 6095 6096 6097 6098 6099

cleanup:
    virDomainSnapshotDefFree(def);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
6100
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6101 6102 6103 6104 6105
    return ret;
}

static int
vboxDomainSnapshotNum(virDomainPtr dom,
6106
                      unsigned int flags)
J
Jiri Denemark 已提交
6107 6108
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6109
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6110 6111 6112 6113
    IMachine *machine = NULL;
    nsresult rc;
    PRUint32 snapshotCount;

6114 6115
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6116

6117
    vboxIIDFromUUID(&iid, dom->uuid);
6118
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6119
    if (NS_FAILED(rc)) {
6120 6121
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6122 6123 6124
        goto cleanup;
    }

6125 6126 6127 6128 6129 6130
    /* VBox snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

J
Jiri Denemark 已提交
6131 6132
    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
    if (NS_FAILED(rc)) {
6133 6134 6135
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6136 6137 6138
        goto cleanup;
    }

6139 6140 6141 6142 6143
    /* VBox has at most one root snapshot.  */
    if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
        ret = 1;
    else
        ret = snapshotCount;
J
Jiri Denemark 已提交
6144 6145 6146

cleanup:
    VBOX_RELEASE(machine);
6147
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6148 6149 6150 6151 6152 6153 6154
    return ret;
}

static int
vboxDomainSnapshotListNames(virDomainPtr dom,
                            char **names,
                            int nameslen,
6155
                            unsigned int flags)
J
Jiri Denemark 已提交
6156 6157
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6158
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6159 6160 6161 6162
    IMachine *machine = NULL;
    nsresult rc;
    ISnapshot **snapshots = NULL;
    int count = 0;
6163
    size_t i;
J
Jiri Denemark 已提交
6164

6165 6166
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6167

6168
    vboxIIDFromUUID(&iid, dom->uuid);
6169
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6170
    if (NS_FAILED(rc)) {
6171 6172
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6173 6174 6175
        goto cleanup;
    }

6176 6177 6178 6179 6180
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

6181 6182 6183
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
        vboxIID empty = VBOX_IID_INITIALIZER;

6184
        if (VIR_ALLOC_N(snapshots, 1) < 0)
6185 6186 6187 6188 6189 6190 6191
            goto cleanup;
#if VBOX_API_VERSION < 4000
        rc = machine->vtbl->GetSnapshot(machine, empty.value, snapshots);
#else /* VBOX_API_VERSION >= 4000 */
        rc = machine->vtbl->FindSnapshot(machine, empty.value, snapshots);
#endif /* VBOX_API_VERSION >= 4000 */
        if (NS_FAILED(rc) || !snapshots[0]) {
6192 6193 6194
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get root snapshot for domain %s"),
                           dom->name);
6195 6196 6197 6198 6199 6200 6201
            goto cleanup;
        }
        count = 1;
    } else {
        if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
            goto cleanup;
    }
J
Jiri Denemark 已提交
6202 6203 6204 6205 6206 6207 6208 6209 6210 6211

    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) {
6212 6213
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
6214 6215 6216 6217
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &name);
        VBOX_UTF16_FREE(nameUtf16);
6218 6219
        if (VIR_STRDUP(names[i], name) < 0) {
            VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
6220 6221
            goto cleanup;
        }
6222
        VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236
    }

    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);
6237
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6238 6239 6240 6241 6242 6243
    return ret;
}

static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,
                               const char *name,
6244
                               unsigned int flags)
J
Jiri Denemark 已提交
6245 6246
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6247
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6248 6249 6250 6251
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

6252 6253
    virCheckFlags(0, NULL);

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

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

    ret = virGetDomainSnapshot(dom, name);

cleanup:
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
6270
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6271 6272 6273 6274 6275
    return ret;
}

static int
vboxDomainHasCurrentSnapshot(virDomainPtr dom,
6276
                             unsigned int flags)
J
Jiri Denemark 已提交
6277 6278
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6279
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6280 6281 6282 6283
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

6284 6285
    virCheckFlags(0, -1);

6286
    vboxIIDFromUUID(&iid, dom->uuid);
6287
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6288
    if (NS_FAILED(rc)) {
6289 6290
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6291 6292 6293 6294 6295
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6296 6297
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
6298 6299 6300 6301 6302 6303 6304 6305 6306 6307
        goto cleanup;
    }

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

cleanup:
    VBOX_RELEASE(machine);
6308
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6309 6310 6311
    return ret;
}

6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330
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)) {
6331 6332
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6333 6334 6335 6336 6337 6338 6339 6340
        goto cleanup;
    }

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

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
6341 6342 6343
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
6344 6345 6346
        goto cleanup;
    }
    if (!parent) {
6347 6348 6349
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshot->name);
6350 6351 6352 6353 6354
        goto cleanup;
    }

    rc = parent->vtbl->GetName(parent, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6355 6356 6357
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get name of parent of snapshot %s"),
                       snapshot->name);
6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377
        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 已提交
6378 6379
static virDomainSnapshotPtr
vboxDomainSnapshotCurrent(virDomainPtr dom,
6380
                          unsigned int flags)
J
Jiri Denemark 已提交
6381 6382
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6383
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6384 6385 6386 6387 6388 6389
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

6390 6391
    virCheckFlags(0, NULL);

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

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6402 6403
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
6404 6405 6406 6407
        goto cleanup;
    }

    if (!snapshot) {
6408 6409
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain has no snapshots"));
J
Jiri Denemark 已提交
6410 6411 6412 6413 6414
        goto cleanup;
    }

    rc = snapshot->vtbl->GetName(snapshot, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6415 6416
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
J
Jiri Denemark 已提交
6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432
        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);
6433
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6434 6435 6436
    return ret;
}

6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455
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)) {
6456 6457
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6458 6459 6460 6461 6462 6463 6464 6465
        goto cleanup;
    }

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

    rc = machine->vtbl->GetCurrentSnapshot(machine, &current);
    if (NS_FAILED(rc)) {
6466 6467
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
6468 6469 6470 6471 6472 6473 6474 6475 6476
        goto cleanup;
    }
    if (!current) {
        ret = 0;
        goto cleanup;
    }

    rc = current->vtbl->GetName(current, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6477 6478
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515
        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)) {
6516 6517
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533
        goto cleanup;
    }

    /* Check that snapshot exists.  If so, there is no metadata.  */
    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    ret = 0;

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

J
Jiri Denemark 已提交
6534 6535 6536 6537 6538 6539 6540
#if VBOX_API_VERSION < 3001
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6541
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6542 6543
    nsresult rc;

6544 6545
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
6546 6547
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
6548 6549 6550
        goto cleanup;
    }

6551
    rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value);
J
Jiri Denemark 已提交
6552
    if (NS_FAILED(rc)) {
6553 6554
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
6555 6556 6557 6558 6559 6560
        goto cleanup;
    }

    ret = 0;

cleanup:
6561
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575
    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;
6576
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6577

6578 6579
    rc = machine->vtbl->GetId(machine, &domiid.value);
    if (NS_FAILED(rc)) {
6580 6581
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain UUID"));
J
Jiri Denemark 已提交
6582 6583 6584 6585 6586
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6587 6588
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6589 6590 6591 6592 6593
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6594 6595
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s is already running"), dom->name);
J
Jiri Denemark 已提交
6596 6597 6598
        goto cleanup;
    }

6599
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6600 6601 6602
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6603 6604 6605
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6606 6607 6608 6609 6610 6611
        goto cleanup;
    }

    rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress);
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
6612 6613
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot restore domain snapshot for running domain"));
J
Jiri Denemark 已提交
6614
        } else {
6615 6616 6617
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not restore snapshot for domain %s"),
                           dom->name);
J
Jiri Denemark 已提交
6618 6619 6620 6621 6622 6623 6624
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6625 6626
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
6627 6628 6629 6630 6631 6632 6633 6634
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(progress);
    VBOX_RELEASE(console);
6635
    VBOX_SESSION_CLOSE();
6636
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6637 6638 6639 6640 6641 6642
    return ret;
}
#endif

static int
vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
6643
                           unsigned int flags)
J
Jiri Denemark 已提交
6644 6645 6646
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6647
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6648 6649 6650 6651 6652 6653 6654
    IMachine *machine = NULL;
    ISnapshot *newSnapshot = NULL;
    ISnapshot *prevSnapshot = NULL;
    PRBool online = PR_FALSE;
    PRUint32 state;
    nsresult rc;

6655 6656
    virCheckFlags(0, -1);

6657
    vboxIIDFromUUID(&domiid, dom->uuid);
6658
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6659
    if (NS_FAILED(rc)) {
6660 6661
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6662 6663 6664 6665 6666 6667 6668 6669 6670
        goto cleanup;
    }

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

    rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online);
    if (NS_FAILED(rc)) {
6671 6672 6673
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6674 6675 6676 6677 6678
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot);
    if (NS_FAILED(rc)) {
6679 6680 6681
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6682 6683 6684 6685 6686
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6687 6688
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6689 6690 6691 6692 6693
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6694 6695
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot revert snapshot of running domain"));
J
Jiri Denemark 已提交
6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711
        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);
6712
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6713 6714 6715 6716 6717 6718 6719 6720 6721
    return ret;
}

static int
vboxDomainSnapshotDeleteSingle(vboxGlobalData *data,
                               IConsole *console,
                               ISnapshot *snapshot)
{
    IProgress *progress = NULL;
6722
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6723 6724 6725 6726 6727 6728 6729 6730
    int ret = -1;
    nsresult rc;
#if VBOX_API_VERSION == 2002
    nsresult result;
#else
    PRInt32 result;
#endif

6731 6732
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
6733 6734
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
6735 6736 6737 6738
        goto cleanup;
    }

#if VBOX_API_VERSION < 3001
6739
    rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6740
#else
6741
    rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6742 6743 6744
#endif
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
6745 6746
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot delete domain snapshot for running domain"));
J
Jiri Denemark 已提交
6747
        } else {
6748 6749
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("could not delete snapshot"));
J
Jiri Denemark 已提交
6750 6751 6752 6753 6754 6755 6756
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6757 6758
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not delete snapshot"));
J
Jiri Denemark 已提交
6759 6760 6761 6762 6763 6764 6765
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(progress);
6766
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6767 6768 6769 6770 6771 6772 6773 6774
    return ret;
}

static int
vboxDomainSnapshotDeleteTree(vboxGlobalData *data,
                             IConsole *console,
                             ISnapshot *snapshot)
{
6775
    vboxArray children = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
6776 6777
    int ret = -1;
    nsresult rc;
6778
    size_t i;
J
Jiri Denemark 已提交
6779

6780
    rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
J
Jiri Denemark 已提交
6781
    if (NS_FAILED(rc)) {
6782 6783
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get children snapshots"));
J
Jiri Denemark 已提交
6784 6785 6786
        goto cleanup;
    }

6787 6788 6789
    for (i = 0; i < children.count; i++) {
        if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
            goto cleanup;
J
Jiri Denemark 已提交
6790 6791 6792 6793 6794
    }

    ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);

cleanup:
6795
    vboxArrayRelease(&children);
J
Jiri Denemark 已提交
6796 6797 6798 6799 6800 6801 6802 6803 6804
    return ret;
}

static int
vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                         unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6805
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6806 6807 6808 6809 6810 6811
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    IConsole *console = NULL;
    PRUint32 state;
    nsresult rc;

6812 6813
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
6814

6815
    vboxIIDFromUUID(&domiid, dom->uuid);
6816
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6817
    if (NS_FAILED(rc)) {
6818 6819
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6820 6821 6822 6823 6824 6825 6826 6827 6828
        goto cleanup;
    }

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

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

6834 6835 6836 6837 6838 6839 6840
    /* 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 已提交
6841 6842
    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6843 6844
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot delete snapshots of running domain"));
J
Jiri Denemark 已提交
6845 6846 6847
        goto cleanup;
    }

6848
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6849 6850 6851
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6852 6853 6854
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865
        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);
6866
    vboxIIDUnalloc(&domiid);
6867
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6868 6869 6870
    return ret;
}

6871
#if VBOX_API_VERSION <= 2002 || VBOX_API_VERSION >= 4000
6872
    /* No Callback support for VirtualBox 2.2.* series */
6873 6874
    /* No Callback support for VirtualBox 4.* series */
#else /* !(VBOX_API_VERSION == 2002 || VBOX_API_VERSION >= 4000) */
6875 6876

/* Functions needed for Callbacks */
6877
static nsresult PR_COM_METHOD
6878
vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6879 6880
                                 PRUnichar *machineId, PRUint32 state)
{
6881 6882 6883 6884 6885 6886
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

6887
    VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
6888 6889 6890 6891 6892 6893 6894
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
6895
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
6896 6897 6898

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
6899
            virDomainEventPtr ev;
6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929

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

6930 6931
            ev = virDomainEventNewFromDom(dom, event, detail);

6932 6933
            if (ev)
                virDomainEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
6934 6935 6936 6937 6938 6939 6940 6941
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

6942
static nsresult PR_COM_METHOD
6943
vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6944 6945
                                PRUnichar *machineId)
{
6946
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
6947 6948 6949 6950 6951
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

6952
static nsresult PR_COM_METHOD
6953
vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6954 6955 6956
                                 PRUnichar *machineId, PRUnichar *key,
                                 PRUnichar *value,
                                 PRUnichar **error ATTRIBUTE_UNUSED,
6957
                                 PRBool *allowChange ATTRIBUTE_UNUSED)
6958
{
6959
    VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
6960 6961 6962 6963 6964 6965 6966
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

6967
static nsresult PR_COM_METHOD
6968 6969
vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *machineId,
6970 6971
                              PRUnichar *key, PRUnichar *value)
{
6972
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
6973 6974 6975 6976 6977 6978 6979
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

6980
# if VBOX_API_VERSION < 3001
6981
static nsresult PR_COM_METHOD
6982 6983 6984 6985
vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *mediaId,
                              PRUint32 mediaType ATTRIBUTE_UNUSED,
                              PRBool registered ATTRIBUTE_UNUSED)
6986
{
6987 6988
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    VIR_DEBUG("mediaType: %d", mediaType);
6989 6990 6991 6992
    DEBUGPRUnichar("mediaId", mediaId);

    return NS_OK;
}
6993 6994
# else  /* VBOX_API_VERSION >= 3001 */
# endif /* VBOX_API_VERSION >= 3001 */
6995

6996
static nsresult PR_COM_METHOD
6997
vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6998 6999
                                PRUnichar *machineId, PRBool registered)
{
7000 7001 7002 7003 7004 7005
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

7006
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
7007 7008 7009 7010 7011 7012 7013
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
7014
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
7015 7016 7017

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
7018
            virDomainEventPtr ev;
7019 7020

            /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
J
Ján Tomko 已提交
7021
             * event because the when the machine is de-registered the call
7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033
             * 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;
            }

7034 7035
            ev = virDomainEventNewFromDom(dom, event, detail);

7036 7037
            if (ev)
                virDomainEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
7038 7039 7040 7041 7042 7043 7044 7045
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

7046
static nsresult PR_COM_METHOD
7047 7048 7049
vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                 PRUnichar *machineId,
                                 PRUint32 state ATTRIBUTE_UNUSED)
7050
{
7051
    VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
7052 7053 7054 7055 7056
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

7057
static nsresult PR_COM_METHOD
7058 7059
vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                            PRUnichar *machineId,
7060 7061
                            PRUnichar *snapshotId)
{
7062
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7063 7064 7065 7066 7067 7068
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7069
static nsresult PR_COM_METHOD
7070 7071
vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                PRUnichar *machineId,
7072 7073
                                PRUnichar *snapshotId)
{
7074
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7075 7076 7077 7078 7079 7080
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

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

    return NS_OK;
}

7093
static nsresult PR_COM_METHOD
7094
vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7095 7096 7097
                                  PRUnichar *machineId, PRUnichar *name,
                                  PRUnichar *value, PRUnichar *flags)
{
7098
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7099 7100 7101 7102 7103 7104 7105 7106
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("name", name);
    DEBUGPRUnichar("value", value);
    DEBUGPRUnichar("flags", flags);

    return NS_OK;
}

7107
static nsresult PR_COM_METHOD
7108
vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
7109
{
7110 7111 7112 7113
    nsresult c;

    c = ++g_pVBoxGlobalData->vboxCallBackRefCount;

7114
    VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);
7115 7116 7117 7118

    return c;
}

7119 7120 7121
static nsresult PR_COM_METHOD
vboxCallbackRelease(nsISupports *pThis)
{
7122 7123 7124 7125 7126 7127 7128 7129 7130
    nsresult c;

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

7131
    VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);
7132 7133 7134 7135

    return c;
}

7136 7137 7138
static nsresult PR_COM_METHOD
vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp)
{
7139 7140 7141 7142 7143
    IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
    static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
    static const nsID isupportIID = NS_ISUPPORTS_IID;

    /* Match UUID for IVirtualBoxCallback class */
7144 7145
    if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 ||
        memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
7146 7147 7148
        g_pVBoxGlobalData->vboxCallBackRefCount++;
        *resultp = that;

7149
        VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);
7150 7151 7152 7153 7154

        return NS_OK;
    }


7155
    VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
7156 7157 7158 7159 7160 7161
    DEBUGUUID("The UUID Callback Interface expects", iid);
    DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
    return NS_NOINTERFACE;
}


7162
static IVirtualBoxCallback *vboxAllocCallbackObj(void) {
7163 7164
    IVirtualBoxCallback *vboxCallback = NULL;

7165
    /* Allocate, Initialize and return a valid
7166 7167 7168
     * IVirtualBoxCallback object here
     */
    if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
7169
        VIR_FREE(vboxCallback);
7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180
        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;
7181
# if VBOX_API_VERSION < 3001
7182
        vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
7183 7184
# else  /* VBOX_API_VERSION >= 3001 */
# endif /* VBOX_API_VERSION >= 3001 */
7185 7186 7187
        vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
        vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
        vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
7188
# if VBOX_API_VERSION < 3002
7189
        vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
7190 7191 7192
# else /* VBOX_API_VERSION >= 3002 */
        vboxCallback->vtbl->OnSnapshotDeleted           = &vboxCallbackOnSnapshotDiscarded;
# endif /* VBOX_API_VERSION >= 3002 */
7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217
        vboxCallback->vtbl->OnSnapshotChange            = &vboxCallbackOnSnapshotChange;
        vboxCallback->vtbl->OnGuestPropertyChange       = &vboxCallbackOnGuestPropertyChange;
        g_pVBoxGlobalData->vboxCallBackRefCount = 1;

    }

    return vboxCallback;
}

static void vboxReadCallback(int watch ATTRIBUTE_UNUSED,
                             int fd,
                             int events ATTRIBUTE_UNUSED,
                             void *opaque ATTRIBUTE_UNUSED) {
    if (fd >= 0) {
        g_pVBoxGlobalData->vboxQueue->vtbl->ProcessPendingEvents(g_pVBoxGlobalData->vboxQueue);
    } else {
        nsresult rc;
        PLEvent *pEvent = NULL;

        rc = g_pVBoxGlobalData->vboxQueue->vtbl->WaitForEvent(g_pVBoxGlobalData->vboxQueue, &pEvent);
        if (NS_SUCCEEDED(rc))
            g_pVBoxGlobalData->vboxQueue->vtbl->HandleEvent(g_pVBoxGlobalData->vboxQueue, pEvent);
    }
}

7218 7219 7220 7221
static int vboxConnectDomainEventRegister(virConnectPtr conn,
                                          virConnectDomainEventCallback callback,
                                          void *opaque,
                                          virFreeCallback freecb) {
7222
    VBOX_OBJECT_CHECK(conn, int, -1);
7223
    int vboxRet          = -1;
7224
    nsresult rc;
7225 7226 7227 7228 7229 7230

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

7231
    if (data->vboxCallback == NULL) {
7232
        data->vboxCallback = vboxAllocCallbackObj();
7233 7234 7235 7236
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
7237 7238
            }
        }
7239 7240 7241
    } else {
        vboxRet = 0;
    }
7242

7243 7244 7245 7246 7247 7248 7249
    /* 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);
7250

7251 7252
            data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
        }
7253

7254 7255 7256 7257 7258
        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
             */
7259

7260 7261
            ret = virDomainEventStateRegister(conn, data->domainEvents,
                                              callback, opaque, freecb);
7262
            VIR_DEBUG("virDomainEventStateRegister (ret = %d) (conn: %p, "
7263
                      "callback: %p, opaque: %p, "
7264
                      "freecb: %p)", ret, conn, callback,
7265
                      opaque, freecb);
7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280
        }
    }

    vboxDriverUnlock(data);

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

7281 7282
static int vboxConnectDomainEventDeregister(virConnectPtr conn,
                                            virConnectDomainEventCallback callback) {
7283
    VBOX_OBJECT_CHECK(conn, int, -1);
7284
    int cnt;
7285 7286 7287 7288 7289 7290

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

7291 7292
    cnt = virDomainEventStateDeregister(conn, data->domainEvents,
                                        callback);
7293

7294 7295 7296
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7297

7298 7299 7300
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7301 7302 7303 7304 7305 7306 7307
    }

    vboxDriverUnlock(data);

    return ret;
}

7308 7309 7310 7311 7312 7313
static int vboxConnectDomainEventRegisterAny(virConnectPtr conn,
                                             virDomainPtr dom,
                                             int eventID,
                                             virConnectDomainEventGenericCallback callback,
                                             void *opaque,
                                             virFreeCallback freecb) {
7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351
    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
             */

7352 7353 7354
            if (virDomainEventStateRegisterID(conn, data->domainEvents,
                                              dom, eventID,
                                              callback, opaque, freecb, &ret) < 0)
7355
                ret = -1;
7356
            VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, "
7357
                      "callback: %p, opaque: %p, "
7358
                      "freecb: %p)", ret, conn, callback,
7359
                      opaque, freecb);
7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374
        }
    }

    vboxDriverUnlock(data);

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

7375 7376
static int vboxConnectDomainEventDeregisterAny(virConnectPtr conn,
                                               int callbackID) {
7377
    VBOX_OBJECT_CHECK(conn, int, -1);
7378
    int cnt;
7379 7380 7381 7382 7383 7384

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

7385 7386
    cnt = virDomainEventStateDeregisterID(conn, data->domainEvents,
                                          callbackID);
7387

7388 7389 7390
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7391

7392 7393 7394
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7395 7396 7397 7398 7399 7400 7401
    }

    vboxDriverUnlock(data);

    return ret;
}

7402
#endif /* !(VBOX_API_VERSION == 2002 || VBOX_API_VERSION >= 4000) */
7403

7404 7405 7406 7407 7408
/**
 * The Network Functions here on
 */
static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
7409 7410
                                        unsigned int flags)
{
7411 7412
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
7413 7414
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

7415 7416 7417 7418 7419 7420 7421 7422
    if (STRNEQ(conn->driver->name, "VBOX"))
        goto cleanup;

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
        goto cleanup;

7423
    VIR_DEBUG("network initialized");
7424 7425 7426 7427 7428 7429 7430 7431
    /* conn->networkPrivateData = some network specific data */
    return VIR_DRV_OPEN_SUCCESS;

cleanup:
    return VIR_DRV_OPEN_DECLINED;
}

static int vboxNetworkClose(virConnectPtr conn) {
7432
    VIR_DEBUG("network uninitialized");
7433 7434 7435 7436
    conn->networkPrivateData = NULL;
    return 0;
}

7437
static int vboxConnectNumOfNetworks(virConnectPtr conn) {
7438
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7439
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7440
    size_t i = 0;
7441

7442
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7443

7444 7445 7446 7447
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7448
            PRUint32 interfaceType = 0;
7449

7450
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7451 7452
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7453

7454
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7455

7456 7457
                if (status == HostNetworkInterfaceStatus_Up)
                    ret++;
7458 7459 7460 7461
            }
        }
    }

7462 7463
    vboxArrayRelease(&networkInterfaces);

7464 7465
    VBOX_RELEASE(host);

7466
    VIR_DEBUG("numActive: %d", ret);
7467
    return ret;
7468 7469
}

7470
static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
7471
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7472
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7473
    size_t i = 0;
7474

7475 7476 7477 7478
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7479

7480
        if (networkInterface) {
7481
            PRUint32 interfaceType = 0;
7482

7483
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7484

7485 7486
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7487

7488
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7489

7490 7491 7492
                if (status == HostNetworkInterfaceStatus_Up) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7493

7494
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7495
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7496

7497
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
7498
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7499
                        ret++;
7500

7501 7502
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7503 7504 7505 7506 7507
                }
            }
        }
    }

7508
    vboxArrayRelease(&networkInterfaces);
7509

7510
    VBOX_RELEASE(host);
7511

7512 7513
    return ret;
}
7514

7515
static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn) {
7516
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7517
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7518
    size_t i = 0;
7519

7520
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7521

7522 7523 7524 7525
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7526
            PRUint32 interfaceType = 0;
7527

7528
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7529 7530
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7531

7532
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7533

7534 7535
                if (status == HostNetworkInterfaceStatus_Down)
                    ret++;
7536 7537 7538 7539
            }
        }
    }

7540 7541
    vboxArrayRelease(&networkInterfaces);

7542 7543
    VBOX_RELEASE(host);

7544
    VIR_DEBUG("numActive: %d", ret);
7545
    return ret;
7546 7547
}

7548
static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
7549
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7550
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7551
    size_t i = 0;
7552

7553 7554 7555 7556
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7557

7558
        if (networkInterface) {
7559
            PRUint32 interfaceType = 0;
7560

7561
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7562

7563 7564
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7565

7566
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7567

7568 7569 7570
                if (status == HostNetworkInterfaceStatus_Down) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7571

7572
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7573
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7574

7575
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
7576
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7577
                        ret++;
7578

7579 7580
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7581 7582 7583 7584 7585
                }
            }
        }
    }

7586
    vboxArrayRelease(&networkInterfaces);
7587 7588 7589 7590

    VBOX_RELEASE(host);

    return ret;
7591 7592
}

7593 7594 7595
static virNetworkPtr
vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
7596
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
7597
    vboxIID iid = VBOX_IID_INITIALIZER;
7598

7599
    vboxIIDFromUUID(&iid, uuid);
7600

7601 7602 7603
    /* TODO: "internal" networks are just strings and
     * thus can't do much with them
     */
7604
    IHostNetworkInterface *networkInterface = NULL;
7605

7606
    host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface);
7607 7608
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7609

7610
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7611

7612 7613 7614
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            char *nameUtf8       = NULL;
            PRUnichar *nameUtf16 = NULL;
7615

7616 7617
            networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
            VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7618

7619
            ret = virGetNetwork(conn, nameUtf8, uuid);
7620

7621
            VIR_DEBUG("Network Name: %s", nameUtf8);
7622
            DEBUGIID("Network UUID", iid.value);
7623

7624 7625
            VBOX_UTF8_FREE(nameUtf8);
            VBOX_UTF16_FREE(nameUtf16);
7626
        }
7627 7628

        VBOX_RELEASE(networkInterface);
7629 7630
    }

7631 7632
    VBOX_RELEASE(host);

7633
    vboxIIDUnalloc(&iid);
7634 7635 7636 7637
    return ret;
}

static virNetworkPtr vboxNetworkLookupByName(virConnectPtr conn, const char *name) {
7638 7639 7640
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *nameUtf16                    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7641

7642
    VBOX_UTF8_TO_UTF16(name, &nameUtf16);
7643

7644
    host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);
7645

7646 7647
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7648

7649
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7650

7651 7652
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            unsigned char uuid[VIR_UUID_BUFLEN];
7653
            vboxIID iid = VBOX_IID_INITIALIZER;
7654

7655 7656
            networkInterface->vtbl->GetId(networkInterface, &iid.value);
            vboxIIDToUUID(&iid, uuid);
7657
            ret = virGetNetwork(conn, name, uuid);
7658
            VIR_DEBUG("Network Name: %s", name);
7659

7660 7661
            DEBUGIID("Network UUID", iid.value);
            vboxIIDUnalloc(&iid);
7662
        }
7663 7664

        VBOX_RELEASE(networkInterface);
7665 7666
    }

7667 7668 7669
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(host);

7670 7671 7672
    return ret;
}

7673
static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start) {
7674 7675 7676 7677
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    char      *networkInterfaceNameUtf8     = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7678
    nsresult rc;
7679

7680
    virNetworkDefPtr def = virNetworkDefParseString(xml);
7681 7682
    virNetworkIpDefPtr ipdef;
    virSocketAddr netmask;
7683

7684
    if ((!def) ||
7685
        (def->forward.type != VIR_NETWORK_FORWARD_NONE) ||
7686
        (def->nips == 0 || !def->ips))
7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697
        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)
7698
        goto cleanup;
7699

7700 7701 7702 7703 7704 7705
    /* 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.
     */
7706

7707
#if VBOX_API_VERSION == 2002
7708
    if (STREQ(def->name, "vboxnet0")) {
7709
        PRUint32 interfaceType = 0;
7710

7711 7712
        VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16);
        host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7713

7714 7715 7716 7717 7718 7719
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
        if (interfaceType != HostNetworkInterfaceType_HostOnly) {
            VBOX_RELEASE(networkInterface);
            networkInterface = NULL;
        }
    }
7720
#else /* VBOX_API_VERSION != 2002 */
7721 7722 7723 7724
    {
        IProgress *progress = NULL;
        host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface,
                                                   &progress);
7725

7726 7727 7728 7729
        if (progress) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
7730
    }
7731
#endif /* VBOX_API_VERSION != 2002 */
7732

7733 7734 7735 7736
    if (networkInterface) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        char      *networkNameUtf8  = NULL;
        PRUnichar *networkNameUtf16 = NULL;
7737
        vboxIID vboxnetiid = VBOX_IID_INITIALIZER;
7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748

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

E
Eric Blake 已提交
7750
        VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
7751

7752 7753 7754
        /* Currently support only one dhcp server per network
         * with contigious address space from start to end
         */
7755
        if ((ipdef->nranges >= 1) &&
7756 7757
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
7758 7759 7760 7761 7762 7763 7764 7765 7766 7767
            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);
7768
                VIR_DEBUG("couldn't find dhcp server so creating one");
7769 7770 7771 7772 7773 7774 7775 7776
            }
            if (dhcpServer) {
                PRUnichar *ipAddressUtf16     = NULL;
                PRUnichar *networkMaskUtf16   = NULL;
                PRUnichar *fromIPAddressUtf16 = NULL;
                PRUnichar *toIPAddressUtf16   = NULL;
                PRUnichar *trunkTypeUtf16     = NULL;

7777 7778 7779 7780
                ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
                networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
                fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
                toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
7781 7782 7783 7784 7785 7786 7787 7788 7789 7790

                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;
                }
7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815

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

7817
        if ((ipdef->nhosts >= 1) &&
7818
            VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) {
7819 7820
            PRUnichar *ipAddressUtf16   = NULL;
            PRUnichar *networkMaskUtf16 = NULL;
7821

7822 7823
            ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
            networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
7824 7825 7826 7827 7828 7829

            if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
                VBOX_UTF16_FREE(ipAddressUtf16);
                VBOX_UTF16_FREE(networkMaskUtf16);
                goto cleanup;
            }
7830

7831 7832 7833 7834
            /* 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
             */
7835
#if VBOX_API_VERSION < 4002
7836 7837 7838
            networkInterface->vtbl->EnableStaticIpConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
7839 7840 7841 7842 7843
#else
            networkInterface->vtbl->EnableStaticIPConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
#endif
7844

7845 7846 7847
            VBOX_UTF16_FREE(ipAddressUtf16);
            VBOX_UTF16_FREE(networkMaskUtf16);
        } else {
7848
#if VBOX_API_VERSION < 4002
7849 7850
            networkInterface->vtbl->EnableDynamicIpConfig(networkInterface);
            networkInterface->vtbl->DhcpRediscover(networkInterface);
7851 7852 7853 7854
#else
            networkInterface->vtbl->EnableDynamicIPConfig(networkInterface);
            networkInterface->vtbl->DHCPRediscover(networkInterface);
#endif
7855
        }
7856

7857 7858 7859 7860 7861
        rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value);
        if (NS_SUCCEEDED(rc)) {
            vboxIIDToUUID(&vboxnetiid, uuid);
            DEBUGIID("Real Network UUID", vboxnetiid.value);
            vboxIIDUnalloc(&vboxnetiid);
7862
            ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid);
7863
        }
7864 7865 7866 7867

        VIR_FREE(networkNameUtf8);
        VBOX_UTF16_FREE(networkNameUtf16);
        VBOX_RELEASE(networkInterface);
7868 7869
    }

7870 7871 7872 7873
    VBOX_UTF8_FREE(networkInterfaceNameUtf8);
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

7874 7875 7876 7877 7878
cleanup:
    virNetworkDefFree(def);
    return ret;
}

7879 7880 7881 7882 7883 7884 7885 7886
static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml) {
    return vboxNetworkDefineCreateXML(conn, xml, true);
}

static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml) {
    return vboxNetworkDefineCreateXML(conn, xml, false);
}

7887
static int vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface) {
7888
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
7889
    char *networkNameUtf8 = NULL;
7890 7891
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7892 7893 7894 7895 7896 7897 7898 7899 7900

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

7901
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
7902 7903
        goto cleanup;

7904
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
7905

7906
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7907

7908 7909
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7910

7911
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7912

7913 7914 7915
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
7916

7917
#if VBOX_API_VERSION != 2002
7918 7919 7920
            if (removeinterface) {
                PRUnichar *iidUtf16 = NULL;
                IProgress *progress = NULL;
7921

7922
                networkInterface->vtbl->GetId(networkInterface, &iidUtf16);
7923

7924
                if (iidUtf16) {
7925
# if VBOX_API_VERSION == 3000
7926 7927 7928
                    IHostNetworkInterface *netInt = NULL;
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress);
                    VBOX_RELEASE(netInt);
7929
# else  /* VBOX_API_VERSION > 3000 */
7930
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress);
7931
# endif /* VBOX_API_VERSION > 3000 */
7932 7933
                    VBOX_UTF16_FREE(iidUtf16);
                }
7934

7935 7936 7937 7938 7939
                if (progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
                }
            }
7940 7941
#endif /* VBOX_API_VERSION != 2002 */

E
Eric Blake 已提交
7942
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
7943 7944 7945 7946 7947 7948 7949 7950 7951 7952

            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);
7953 7954
            }

7955 7956
            VBOX_UTF16_FREE(networkNameUtf16);

7957
        }
7958
        VBOX_RELEASE(networkInterface);
7959 7960
    }

7961 7962 7963
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

7964 7965 7966 7967 7968 7969 7970
    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

7971 7972 7973 7974
static int vboxNetworkUndefine(virNetworkPtr network) {
    return vboxNetworkUndefineDestroy(network, true);
}

7975
static int vboxNetworkCreate(virNetworkPtr network) {
7976
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
7977
    char *networkNameUtf8 = NULL;
7978 7979
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7980 7981 7982 7983 7984 7985 7986 7987

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

7988
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
7989 7990
        goto cleanup;

7991
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
7992

7993
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7994

7995 7996
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7997

7998
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7999

8000 8001 8002
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
8003 8004


E
Eric Blake 已提交
8005
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8006

8007 8008 8009 8010 8011
            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                PRUnichar *trunkTypeUtf16 = NULL;
8012

8013
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
8014

8015
                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
8016

8017 8018 8019 8020
                dhcpServer->vtbl->Start(dhcpServer,
                                        networkNameUtf16,
                                        networkInterfaceNameUtf16,
                                        trunkTypeUtf16);
8021

8022 8023
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
8024 8025
            }

8026
            VBOX_UTF16_FREE(networkNameUtf16);
8027
        }
8028 8029

        VBOX_RELEASE(networkInterface);
8030 8031
    }

8032 8033 8034
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8035 8036 8037 8038 8039 8040 8041 8042
    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

static int vboxNetworkDestroy(virNetworkPtr network) {
8043
    return vboxNetworkUndefineDestroy(network, false);
8044 8045
}

8046
static char *vboxNetworkGetXMLDesc(virNetworkPtr network,
E
Eric Blake 已提交
8047 8048
                                   unsigned int flags)
{
8049
    VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
8050
    virNetworkDefPtr def  = NULL;
8051
    virNetworkIpDefPtr ipdef = NULL;
8052
    char *networkNameUtf8 = NULL;
8053 8054
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
8055

E
Eric Blake 已提交
8056 8057
    virCheckFlags(0, NULL);

8058
    if (VIR_ALLOC(def) < 0)
8059
        goto cleanup;
8060
    if (VIR_ALLOC(ipdef) < 0)
8061 8062 8063
        goto cleanup;
    def->ips = ipdef;
    def->nips = 1;
8064

8065
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
8066 8067
        goto cleanup;

8068
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8069

8070
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8071

8072 8073
    if (networkInterface) {
        PRUint32 interfaceType = 0;
8074

8075
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8076

8077
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
J
Ján Tomko 已提交
8078
            if (VIR_STRDUP(def->name, network->name) >= 0) {
8079 8080
                PRUnichar *networkNameUtf16 = NULL;
                IDHCPServer *dhcpServer     = NULL;
8081
                vboxIID vboxnet0IID = VBOX_IID_INITIALIZER;
8082

8083 8084
                networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value);
                vboxIIDToUUID(&vboxnet0IID, def->uuid);
8085

E
Eric Blake 已提交
8086
                VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8087

8088
                def->forward.type = VIR_NETWORK_FORWARD_NONE;
8089

8090 8091 8092 8093
                data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                 networkNameUtf16,
                                                                 &dhcpServer);
                if (dhcpServer) {
8094
                    ipdef->nranges = 1;
8095
                    if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >=0) {
8096 8097 8098 8099
                        PRUnichar *ipAddressUtf16     = NULL;
                        PRUnichar *networkMaskUtf16   = NULL;
                        PRUnichar *fromIPAddressUtf16 = NULL;
                        PRUnichar *toIPAddressUtf16   = NULL;
8100
                        bool errorOccurred = false;
8101

8102 8103 8104 8105 8106 8107 8108
                        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
                         */
8109
                        if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8110
                                                     &ipdef->address) < 0 ||
8111
                            vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8112
                                                     &ipdef->netmask) < 0 ||
8113
                            vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
8114
                                                     &ipdef->ranges[0].start) < 0 ||
8115
                            vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
8116
                                                     &ipdef->ranges[0].end) < 0) {
8117 8118
                            errorOccurred = true;
                        }
8119 8120 8121 8122 8123

                        VBOX_UTF16_FREE(ipAddressUtf16);
                        VBOX_UTF16_FREE(networkMaskUtf16);
                        VBOX_UTF16_FREE(fromIPAddressUtf16);
                        VBOX_UTF16_FREE(toIPAddressUtf16);
8124 8125 8126 8127

                        if (errorOccurred) {
                            goto cleanup;
                        }
8128
                    } else {
8129
                        ipdef->nranges = 0;
8130
                    }
8131

8132
                    ipdef->nhosts = 1;
8133
                    if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >=0) {
8134
                        if (VIR_STRDUP(ipdef->hosts[0].name, network->name) < 0) {
8135 8136
                            VIR_FREE(ipdef->hosts);
                            ipdef->nhosts = 0;
8137
                        } else {
8138 8139
                            PRUnichar *macAddressUtf16 = NULL;
                            PRUnichar *ipAddressUtf16  = NULL;
8140
                            bool errorOccurred = false;
8141

8142
                            networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
8143 8144
                            networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

8145
                            VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
8146 8147

                            if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8148
                                                         &ipdef->hosts[0].ip) < 0) {
8149 8150
                                errorOccurred = true;
                            }
8151

8152 8153
                            VBOX_UTF16_FREE(macAddressUtf16);
                            VBOX_UTF16_FREE(ipAddressUtf16);
8154 8155 8156 8157

                            if (errorOccurred) {
                                goto cleanup;
                            }
8158 8159
                        }
                    } else {
8160
                        ipdef->nhosts = 0;
8161
                    }
8162 8163 8164 8165 8166

                    VBOX_RELEASE(dhcpServer);
                } else {
                    PRUnichar *networkMaskUtf16 = NULL;
                    PRUnichar *ipAddressUtf16   = NULL;
8167
                    bool errorOccurred = false;
8168 8169 8170 8171

                    networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16);
                    networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

8172
                    if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8173
                                                 &ipdef->netmask) < 0 ||
8174
                        vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8175
                                                 &ipdef->address) < 0) {
8176 8177
                        errorOccurred = true;
                    }
8178 8179 8180

                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(ipAddressUtf16);
8181 8182 8183 8184

                    if (errorOccurred) {
                        goto cleanup;
                    }
8185 8186
                }

8187 8188
                DEBUGIID("Network UUID", vboxnet0IID.value);
                vboxIIDUnalloc(&vboxnet0IID);
8189
                VBOX_UTF16_FREE(networkNameUtf16);
8190 8191
            }
        }
8192 8193

        VBOX_RELEASE(networkInterface);
8194 8195
    }

8196 8197 8198
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8199
    ret = virNetworkDefFormat(def, 0);
8200 8201

cleanup:
8202
    virNetworkDefFree(def);
8203 8204 8205 8206
    VIR_FREE(networkNameUtf8);
    return ret;
}

8207 8208 8209 8210
/**
 * The Storage Functions here on
 */

8211 8212 8213
static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
8214
{
8215 8216
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
8217 8218
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

8219
    if (STRNEQ(conn->driver->name, "VBOX"))
8220
        return VIR_DRV_OPEN_DECLINED;
8221 8222 8223 8224

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
8225
        return VIR_DRV_OPEN_ERROR;
8226

8227
    VIR_DEBUG("vbox storage initialized");
8228 8229 8230 8231
    /* conn->storagePrivateData = some storage specific data */
    return VIR_DRV_OPEN_SUCCESS;
}

8232
static int vboxStorageClose(virConnectPtr conn) {
8233
    VIR_DEBUG("vbox storage uninitialized");
8234 8235 8236 8237
    conn->storagePrivateData = NULL;
    return 0;
}

8238
static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED) {
8239 8240 8241 8242 8243 8244 8245 8246

    /** Currently only one pool supported, the default one
     * given by ISystemProperties::defaultHardDiskFolder()
     */

    return 1;
}

8247 8248
static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       char **const names, int nnames) {
8249 8250
    int numActive = 0;

8251 8252 8253
    if (nnames == 1 &&
        VIR_STRDUP(names[numActive], "default-pool") > 0)
        numActive++;
8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267
    return numActive;
}

static virStoragePoolPtr vboxStoragePoolLookupByName(virConnectPtr conn, const char *name) {
    virStoragePoolPtr ret = NULL;

    /** Current limitation of the function: since
     * the default pool doesn't have UUID just assign
     * one till vbox can handle pools
     */
    if (STREQ("default-pool", name)) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        const char *uuidstr = "1deff1ff-1481-464f-967f-a50fe8936cc4";

8268
        ignore_value(virUUIDParse(uuidstr, uuid));
8269

8270
        ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
8271 8272 8273 8274 8275 8276
    }

    return ret;
}

static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool) {
8277
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8278
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8279 8280
    PRUint32 hardDiskAccessible = 0;
    nsresult rc;
8281
    size_t i;
8282

8283
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8284
    if (NS_SUCCEEDED(rc)) {
8285 8286
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8287 8288
            if (hardDisk) {
                PRUint32 hddstate;
8289

8290 8291 8292
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible)
                    hardDiskAccessible++;
8293 8294
            }
        }
8295 8296 8297 8298

        vboxArrayRelease(&hardDisks);

        ret = hardDiskAccessible;
8299
    } else {
8300
        ret = -1;
8301 8302 8303
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get number of volumes in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8304 8305
    }

8306
    return ret;
8307 8308 8309
}

static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) {
8310
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8311
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8312 8313
    PRUint32 numActive     = 0;
    nsresult rc;
8314
    size_t i;
8315

8316
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8317
    if (NS_SUCCEEDED(rc)) {
8318 8319
        for (i = 0; i < hardDisks.count && numActive < nnames; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8320

8321 8322 8323 8324
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8325

8326 8327 8328
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8329

8330 8331
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
8332

8333
                    if (nameUtf8) {
8334
                        VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8);
8335
                        if (VIR_STRDUP(names[numActive], nameUtf8) > 0)
8336 8337 8338
                            numActive++;

                        VBOX_UTF8_FREE(nameUtf8);
8339 8340 8341 8342
                    }
                }
            }
        }
8343 8344 8345 8346

        vboxArrayRelease(&hardDisks);

        ret = numActive;
8347
    } else {
8348
        ret = -1;
8349 8350 8351
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get the volume list in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8352 8353
    }

8354
    return ret;
8355 8356 8357
}

static virStorageVolPtr vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name) {
8358
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8359
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8360
    nsresult rc;
8361
    size_t i;
8362

8363
    if (!name)
8364
        return ret;
8365

8366
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8367
    if (NS_SUCCEEDED(rc)) {
8368 8369
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8370

8371 8372 8373 8374
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8375

8376 8377 8378
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8379

8380 8381 8382 8383
                    if (nameUtf16) {
                        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                        VBOX_UTF16_FREE(nameUtf16);
                    }
8384

8385
                    if (nameUtf8 && STREQ(nameUtf8, name)) {
8386 8387 8388
                        vboxIID hddIID = VBOX_IID_INITIALIZER;
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        char key[VIR_UUID_STRING_BUFLEN] = "";
8389

8390 8391 8392 8393
                        rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                        if (NS_SUCCEEDED(rc)) {
                            vboxIIDToUUID(&hddIID, uuid);
                            virUUIDFormat(uuid, key);
8394

8395 8396
                            ret = virGetStorageVol(pool->conn, pool->name, name, key,
                                                   NULL, NULL);
8397

8398 8399 8400 8401
                            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);
8402 8403
                        }

8404
                        vboxIIDUnalloc(&hddIID);
8405 8406
                        VBOX_UTF8_FREE(nameUtf8);
                        break;
8407
                    }
8408

J
John Ferlan 已提交
8409
                    VBOX_UTF8_FREE(nameUtf8);
8410 8411 8412
                }
            }
        }
8413

8414
        vboxArrayRelease(&hardDisks);
8415 8416 8417 8418 8419 8420
    }

    return ret;
}

static virStorageVolPtr vboxStorageVolLookupByKey(virConnectPtr conn, const char *key) {
8421
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8422 8423
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
8424 8425 8426
    IHardDisk *hardDisk  = NULL;
    nsresult rc;

8427 8428 8429
    if (!key)
        return ret;

8430
    if (virUUIDParse(key, uuid) < 0) {
8431 8432
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), key);
8433
        return NULL;
8434 8435
    }

8436
    vboxIIDFromUUID(&hddIID, uuid);
8437
#if VBOX_API_VERSION < 4000
8438
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8439
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
8440 8441
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8442 8443 8444 8445
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8446
#endif /* VBOX_API_VERSION >= 4000 */
8447 8448
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8449

8450 8451 8452 8453
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
8454

8455 8456
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
            VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
8457

8458
            if (hddNameUtf8) {
8459
                if (vboxConnectNumOfStoragePools(conn) == 1) {
8460 8461
                    ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                           NULL, NULL);
8462
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
8463 8464 8465 8466
                } else {
                    /* TODO: currently only one default pool and thus
                     * nothing here, change it when pools are supported
                     */
8467 8468
                }

8469 8470
                VIR_DEBUG("Storage Volume Name: %s", key);
                VIR_DEBUG("Storage Volume key : %s", hddNameUtf8);
8471 8472 8473

                VBOX_UTF8_FREE(hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
8474 8475
            }
        }
8476 8477

        VBOX_MEDIUM_RELEASE(hardDisk);
8478 8479
    }

8480
    vboxIIDUnalloc(&hddIID);
8481 8482 8483 8484
    return ret;
}

static virStorageVolPtr vboxStorageVolLookupByPath(virConnectPtr conn, const char *path) {
8485
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8486 8487 8488 8489
    PRUnichar *hddPathUtf16 = NULL;
    IHardDisk *hardDisk     = NULL;
    nsresult rc;

8490 8491
    if (!path)
        return ret;
8492

8493
    VBOX_UTF8_TO_UTF16(path, &hddPathUtf16);
8494

8495 8496
    if (!hddPathUtf16)
        return ret;
8497

8498
#if VBOX_API_VERSION < 4000
8499
    rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk);
8500
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
8501 8502
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, &hardDisk);
8503 8504 8505 8506
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8507
#endif /* VBOX_API_VERSION >= 4000 */
8508 8509
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8510

8511 8512 8513 8514
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
8515

8516
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
8517

8518 8519 8520 8521
            if (hddNameUtf16) {
                VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
            }
8522

8523 8524 8525 8526
            if (hddNameUtf8) {
                vboxIID hddIID = VBOX_IID_INITIALIZER;
                unsigned char uuid[VIR_UUID_BUFLEN];
                char key[VIR_UUID_STRING_BUFLEN] = "";
8527

8528 8529 8530 8531
                rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                if (NS_SUCCEEDED(rc)) {
                    vboxIIDToUUID(&hddIID, uuid);
                    virUUIDFormat(uuid, key);
8532

8533 8534 8535
                    /* TODO: currently only one default pool and thus
                     * the check below, change it when pools are supported
                     */
8536
                    if (vboxConnectNumOfStoragePools(conn) == 1)
8537 8538
                        ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                               NULL, NULL);
8539

8540 8541 8542
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
                    VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
                    VIR_DEBUG("Storage Volume key : %s", key);
8543
                }
8544

8545
                vboxIIDUnalloc(&hddIID);
8546 8547
            }

J
John Ferlan 已提交
8548
            VBOX_UTF8_FREE(hddNameUtf8);
8549
        }
8550 8551

        VBOX_MEDIUM_RELEASE(hardDisk);
8552 8553
    }

8554 8555
    VBOX_UTF16_FREE(hddPathUtf16);

8556 8557 8558 8559 8560
    return ret;
}

static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
                                                const char *xml,
E
Eric Blake 已提交
8561 8562
                                                unsigned int flags)
{
8563
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8564
    virStorageVolDefPtr  def  = NULL;
8565 8566
    PRUnichar *hddFormatUtf16 = NULL;
    PRUnichar *hddNameUtf16   = NULL;
8567 8568 8569
    virStoragePoolDef poolDef;
    nsresult rc;

E
Eric Blake 已提交
8570 8571
    virCheckFlags(0, NULL);

8572 8573 8574 8575 8576 8577 8578 8579
    /* 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;

8580
    if ((def = virStorageVolDefParseString(&poolDef, xml)) == NULL)
8581 8582
        goto cleanup;

8583 8584
    if (!def->name ||
        (def->type != VIR_STORAGE_VOL_FILE))
8585
        goto cleanup;
8586

8587 8588 8589 8590 8591 8592
    /* 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
     */
8593

8594 8595 8596 8597 8598 8599 8600
    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);
    }
8601

8602
    VBOX_UTF8_TO_UTF16(def->name, &hddNameUtf16);
8603

8604 8605
    if (hddFormatUtf16 && hddNameUtf16) {
        IHardDisk *hardDisk = NULL;
8606

8607 8608 8609
        rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk);
        if (NS_SUCCEEDED(rc)) {
            IProgress *progress    = NULL;
8610
            PRUint64   logicalSize = VIR_DIV_UP(def->capacity, 1024 * 1024);
8611
            PRUint32   variant     = HardDiskVariant_Standard;
8612

8613 8614
            if (def->capacity == def->allocation)
                variant = HardDiskVariant_Fixed;
8615

8616 8617
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
            if (NS_SUCCEEDED(rc) && progress) {
8618
#if VBOX_API_VERSION == 2002
8619
                nsresult resultCode;
8620
#else
8621
                PRInt32  resultCode;
8622 8623
#endif

8624 8625
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
8626

8627
                if (NS_SUCCEEDED(resultCode)) {
8628 8629 8630
                    vboxIID hddIID = VBOX_IID_INITIALIZER;
                    unsigned char uuid[VIR_UUID_BUFLEN];
                    char key[VIR_UUID_STRING_BUFLEN] = "";
8631

8632
                    rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
8633
                    if (NS_SUCCEEDED(rc)) {
8634 8635
                        vboxIIDToUUID(&hddIID, uuid);
                        virUUIDFormat(uuid, key);
8636

8637 8638
                        ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
                                               NULL, NULL);
8639
                    }
8640 8641

                    vboxIIDUnalloc(&hddIID);
8642 8643
                }

8644
                VBOX_RELEASE(progress);
8645
            }
8646
        }
8647 8648
    }

8649 8650 8651
    VBOX_UTF16_FREE(hddFormatUtf16);
    VBOX_UTF16_FREE(hddNameUtf16);

8652 8653 8654 8655 8656 8657
cleanup:
    virStorageVolDefFree(def);
    return ret;
}

static int vboxStorageVolDelete(virStorageVolPtr vol,
E
Eric Blake 已提交
8658 8659
                                unsigned int flags)
{
8660
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
8661 8662
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
8663 8664 8665
    IHardDisk *hardDisk  = NULL;
    int deregister = 0;
    nsresult rc;
8666 8667
    size_t i = 0;
    size_t j = 0;
8668

E
Eric Blake 已提交
8669 8670
    virCheckFlags(0, -1);

8671
    if (virUUIDParse(vol->key, uuid) < 0) {
8672 8673
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8674 8675
        return -1;
    }
8676

8677
    vboxIIDFromUUID(&hddIID, uuid);
8678
#if VBOX_API_VERSION < 4000
8679
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8680
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
8681 8682
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8683 8684 8685 8686
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8687
#endif /* VBOX_API_VERSION >= 4000 */
8688 8689
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8690

8691 8692 8693
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUint32  machineIdsSize = 0;
8694 8695 8696 8697 8698 8699 8700
            vboxArray machineIds = VBOX_ARRAY_INITIALIZER;

#if VBOX_API_VERSION < 3001
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds);
#else  /* VBOX_API_VERSION >= 3001 */
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds);
#endif /* VBOX_API_VERSION >= 3001 */
8701

8702 8703 8704 8705 8706 8707 8708
#if VBOX_API_VERSION == 2002 && defined WIN32
            /* VirtualBox 2.2 on Windows represents IIDs as GUIDs and the
             * machineIds array contains direct instances of the GUID struct
             * instead of pointers to the actual struct instances. But there
             * is no 128bit width simple item type for a SafeArray to fit a
             * GUID in. The largest simple type it 64bit width and VirtualBox
             * uses two of this 64bit items to represents one GUID. Therefore,
J
Ján Tomko 已提交
8709
             * we divide the size of the SafeArray by two, to compensate for
8710 8711 8712 8713
             * this workaround in VirtualBox */
            machineIds.count /= 2;
#endif /* VBOX_API_VERSION >= 2002 */

8714
            machineIdsSize = machineIds.count;
8715

8716
            for (i = 0; i < machineIds.count; i++) {
8717
                IMachine *machine = NULL;
8718 8719 8720
                vboxIID machineId = VBOX_IID_INITIALIZER;

                vboxIIDFromArrayItem(&machineId, &machineIds, i);
8721

8722 8723 8724
#if VBOX_API_VERSION >= 4000
                rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine);
                if (NS_FAILED(rc)) {
8725 8726
                    virReportError(VIR_ERR_NO_DOMAIN, "%s",
                                   _("no domain with matching uuid"));
8727 8728 8729 8730 8731 8732
                    break;
                }
#endif

                rc = VBOX_SESSION_OPEN(machineId.value, machine);

8733
                if (NS_SUCCEEDED(rc)) {
8734

8735 8736
                    rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                    if (NS_SUCCEEDED(rc)) {
8737
                        vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER;
8738 8739

#if VBOX_API_VERSION < 3001
8740 8741
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetHardDiskAttachments);
8742
#else  /* VBOX_API_VERSION >= 3001 */
8743 8744
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetMediumAttachments);
8745
#endif /* VBOX_API_VERSION >= 3001 */
8746 8747
                        for (j = 0; j < hddAttachments.count; j++) {
                            IHardDiskAttachment *hddAttachment = hddAttachments.items[j];
8748 8749 8750 8751 8752 8753 8754 8755 8756 8757

                            if (hddAttachment) {
                                IHardDisk *hdd = NULL;

#if VBOX_API_VERSION < 3001
                                rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd);
#else  /* VBOX_API_VERSION >= 3001 */
                                rc = hddAttachment->vtbl->GetMedium(hddAttachment, &hdd);
#endif /* VBOX_API_VERSION >= 3001 */
                                if (NS_SUCCEEDED(rc) && hdd) {
8758
                                    vboxIID iid = VBOX_IID_INITIALIZER;
8759

8760 8761
                                    rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value);
                                    if (NS_SUCCEEDED(rc)) {
8762

8763 8764
                                            DEBUGIID("HardDisk (to delete) UUID", hddIID.value);
                                            DEBUGIID("HardDisk (currently processing) UUID", iid.value);
8765

8766
                                        if (vboxIIDIsEqual(&hddIID, &iid)) {
8767 8768 8769 8770
                                            PRUnichar *controller = NULL;
                                            PRInt32    port       = 0;
                                            PRInt32    device     = 0;

8771
                                            DEBUGIID("Found HardDisk to delete, UUID", hddIID.value);
8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783

                                            hddAttachment->vtbl->GetController(hddAttachment, &controller);
                                            hddAttachment->vtbl->GetPort(hddAttachment, &port);
                                            hddAttachment->vtbl->GetDevice(hddAttachment, &device);

#if VBOX_API_VERSION < 3001
                                            rc = machine->vtbl->DetachHardDisk(machine, controller, port, device);
#else  /* VBOX_API_VERSION >= 3001 */
                                            rc = machine->vtbl->DetachDevice(machine, controller, port, device);
#endif /* VBOX_API_VERSION >= 3001 */
                                            if (NS_SUCCEEDED(rc)) {
                                                rc = machine->vtbl->SaveSettings(machine);
8784
                                                VIR_DEBUG("saving machine settings");
8785
                                            }
8786

8787 8788
                                            if (NS_SUCCEEDED(rc)) {
                                                deregister++;
8789
                                                VIR_DEBUG("deregistering hdd:%d", deregister);
8790
                                            }
8791

J
John Ferlan 已提交
8792
                                            VBOX_UTF16_FREE(controller);
8793
                                        }
8794
                                        vboxIIDUnalloc(&iid);
8795
                                    }
8796
                                    VBOX_MEDIUM_RELEASE(hdd);
8797 8798 8799
                                }
                            }
                        }
8800
                        vboxArrayRelease(&hddAttachments);
8801
                        VBOX_RELEASE(machine);
8802
                    }
8803
                    VBOX_SESSION_CLOSE();
8804
                }
8805 8806

                vboxIIDUnalloc(&machineId);
8807
            }
8808

8809
            vboxArrayUnalloc(&machineIds);
8810

8811 8812
            if (machineIdsSize == 0 || machineIdsSize == deregister) {
                IProgress *progress = NULL;
8813

8814
                rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress);
8815

8816 8817 8818
                if (NS_SUCCEEDED(rc) && progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
8819
                    DEBUGIID("HardDisk deleted, UUID", hddIID.value);
8820
                    ret = 0;
8821 8822 8823
                }
            }
        }
8824 8825

        VBOX_MEDIUM_RELEASE(hardDisk);
8826 8827
    }

8828
    vboxIIDUnalloc(&hddIID);
8829

8830 8831 8832 8833
    return ret;
}

static int vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info) {
8834
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
8835
    IHardDisk *hardDisk  = NULL;
8836 8837
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
8838 8839
    nsresult rc;

8840
    if (!info)
8841
        return ret;
8842

8843
    if (virUUIDParse(vol->key, uuid) < 0) {
8844 8845
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8846
        return ret;
8847
    }
8848

8849
    vboxIIDFromUUID(&hddIID, uuid);
8850
#if VBOX_API_VERSION < 4000
8851
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8852
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
8853 8854
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8855 8856 8857 8858
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8859
#endif /* VBOX_API_VERSION >= 4000 */
8860 8861
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8862

8863 8864
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
8865
#if VBOX_API_VERSION < 4000
8866 8867
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
8868 8869 8870 8871
#else /* VBOX_API_VERSION >= 4000 */
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
#endif /* VBOX_API_VERSION >= 4000 */
8872

8873
            info->type = VIR_STORAGE_VOL_FILE;
8874

8875
            hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
8876
#if VBOX_API_VERSION < 4000
8877
            info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
8878 8879 8880
#else /* VBOX_API_VERSION >= 4000 */
            info->capacity = hddLogicalSize;
#endif /* VBOX_API_VERSION >= 4000 */
8881

8882 8883
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            info->allocation = hddActualSize;
8884

8885
            ret = 0;
8886

8887 8888 8889 8890
            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);
8891
        }
8892 8893

        VBOX_MEDIUM_RELEASE(hardDisk);
8894 8895
    }

8896
    vboxIIDUnalloc(&hddIID);
8897

8898 8899 8900
    return ret;
}

E
Eric Blake 已提交
8901 8902
static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
{
8903
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
8904
    IHardDisk *hardDisk  = NULL;
8905 8906
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
8907 8908 8909 8910 8911
    virStoragePoolDef pool;
    virStorageVolDef def;
    int defOk = 0;
    nsresult rc;

E
Eric Blake 已提交
8912 8913
    virCheckFlags(0, NULL);

8914 8915 8916
    memset(&pool, 0, sizeof(pool));
    memset(&def, 0, sizeof(def));

8917
    if (virUUIDParse(vol->key, uuid) < 0) {
8918 8919
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8920
        return ret;
8921
    }
8922

8923
    vboxIIDFromUUID(&hddIID, uuid);
8924
#if VBOX_API_VERSION < 4000
8925
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8926
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
8927 8928
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8929 8930 8931 8932
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8933
#endif /* VBOX_API_VERSION >= 4000 */
8934 8935 8936 8937 8938 8939
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;

        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) {
            PRUnichar *hddFormatUtf16 = NULL;
8940
#if VBOX_API_VERSION < 4000
8941 8942
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
8943 8944 8945 8946
#else /* VBOX_API_VERSION >= 4000 */
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
#endif /* VBOX_API_VERSION >= 4000 */
8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957

            /* 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);
8958 8959
            if (NS_SUCCEEDED(rc) && defOk) {
#if VBOX_API_VERSION < 4000
8960
                def.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
8961 8962 8963 8964
#else /* VBOX_API_VERSION >= 4000 */
                def.capacity = hddLogicalSize;
#endif /* VBOX_API_VERSION >= 4000 */
            } else
8965 8966 8967 8968 8969 8970 8971 8972
                defOk = 0;

            rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            if (NS_SUCCEEDED(rc) && defOk)
                def.allocation = hddActualSize;
            else
                defOk = 0;

8973
            if (VIR_STRDUP(def.name, vol->name) < 0)
8974 8975
                defOk = 0;

8976
            if (VIR_STRDUP(def.key, vol->key) < 0)
8977 8978 8979 8980 8981 8982 8983 8984 8985
                defOk = 0;

            rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16);
            if (NS_SUCCEEDED(rc) && defOk) {
                char *hddFormatUtf8 = NULL;

                VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8);
                if (hddFormatUtf8) {

8986
                    VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8);
8987 8988 8989 8990 8991

                    if (STRCASEEQ("vmdk", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VMDK;
                    else if (STRCASEEQ("vhd", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VPC;
8992
                    else
8993
                        def.target.format = VIR_STORAGE_FILE_RAW;
8994

8995 8996 8997
                    /* TODO: need to add vdi to enum virStorageFileFormat {}
                     * and then add it here
                     */
8998

8999
                    VBOX_UTF8_FREE(hddFormatUtf8);
9000 9001
                }

9002 9003 9004
                VBOX_UTF16_FREE(hddFormatUtf16);
            } else {
                defOk = 0;
9005 9006
            }
        }
9007 9008

        VBOX_MEDIUM_RELEASE(hardDisk);
9009 9010
    }

9011
    vboxIIDUnalloc(&hddIID);
9012

9013
    if (defOk)
9014
        ret = virStorageVolDefFormat(&pool, &def);
9015 9016 9017 9018 9019

    return ret;
}

static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
9020
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
9021
    IHardDisk *hardDisk  = NULL;
9022 9023
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
9024 9025
    nsresult rc;

9026
    if (virUUIDParse(vol->key, uuid) < 0) {
9027 9028
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
9029
        return ret;
9030
    }
9031

9032
    vboxIIDFromUUID(&hddIID, uuid);
9033
#if VBOX_API_VERSION < 4000
9034
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9035
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
9036 9037
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
9038 9039 9040 9041
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
9042
#endif /* VBOX_API_VERSION >= 4000 */
9043 9044
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
9045

9046 9047 9048 9049
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddLocationUtf16 = NULL;
            char      *hddLocationUtf8  = NULL;
9050

9051
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16);
9052

9053 9054
            VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8);
            if (hddLocationUtf8) {
9055

9056
                ignore_value(VIR_STRDUP(ret, hddLocationUtf8));
9057

9058 9059 9060
                VIR_DEBUG("Storage Volume Name: %s", vol->name);
                VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8);
                VIR_DEBUG("Storage Volume Pool: %s", vol->pool);
9061

9062
                VBOX_UTF8_FREE(hddLocationUtf8);
9063 9064
            }

9065
            VBOX_UTF16_FREE(hddLocationUtf16);
9066
        }
9067 9068

        VBOX_MEDIUM_RELEASE(hardDisk);
9069 9070
    }

9071
    vboxIIDUnalloc(&hddIID);
9072

9073 9074
    return ret;
}
9075

9076
#if VBOX_API_VERSION >= 4000
9077 9078 9079 9080
static char *
vboxDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
9081
                     unsigned int flags)
9082 9083 9084 9085 9086 9087 9088 9089 9090 9091
{
    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 已提交
9092 9093
    virCheckFlags(0, NULL);

9094 9095 9096
    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
9097 9098
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
9099 9100 9101 9102 9103
        return NULL;
    }

    rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
    if (NS_FAILED(rc)) {
9104 9105
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to get monitor count"));
9106 9107 9108 9109 9110
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (screen >= max_screen) {
9111 9112 9113
        virReportError(VIR_ERR_INVALID_ARG,
                       _("screen ID higher than monitor "
                         "count (%d)"), max_screen);
9114 9115 9116 9117 9118 9119 9120 9121 9122
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
        VBOX_RELEASE(machine);
        return NULL;
    }

9123 9124
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148
        VIR_FREE(tmp);
        VBOX_RELEASE(machine);
        return NULL;
    }


    rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
    if (NS_SUCCEEDED(rc)) {
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (NS_SUCCEEDED(rc) && console) {
            IDisplay *display = NULL;

            console->vtbl->GetDisplay(console, &display);

            if (display) {
                PRUint32 width, height, bitsPerPixel;
                PRUint32 screenDataSize;
                PRUint8 *screenData;

                rc = display->vtbl->GetScreenResolution(display, screen,
                                                        &width, &height,
                                                        &bitsPerPixel);

                if (NS_FAILED(rc) || !width || !height) {
9149 9150
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to get screen resolution"));
9151 9152 9153 9154 9155 9156 9157 9158
                    goto endjob;
                }

                rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
                                                             width, height,
                                                             &screenDataSize,
                                                             &screenData);
                if (NS_FAILED(rc)) {
9159 9160
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("failed to take screenshot"));
9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175
                    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;
                }

9176 9177 9178
                if (VIR_STRDUP(ret, "image/png") < 0)
                    goto endjob;

E
Eric Blake 已提交
9179
                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
9180 9181
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to open stream"));
9182
                    VIR_FREE(ret);
9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193
                }
endjob:
                VIR_FREE(screenData);
                VBOX_RELEASE(display);
            }
            VBOX_RELEASE(console);
        }
        VBOX_SESSION_CLOSE();
    }

    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
9194
    unlink(tmp);
9195 9196 9197 9198 9199
    VIR_FREE(tmp);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}
9200
#endif /* VBOX_API_VERSION >= 4000 */
9201

9202 9203 9204

#define MATCH(FLAG) (flags & (FLAG))
static int
9205 9206 9207
vboxConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
9208 9209 9210 9211 9212 9213 9214 9215 9216
{
    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;
9217
    size_t i;
9218 9219 9220 9221 9222 9223
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    int count = 0;
    bool active;
    PRUint32 snapshotCount;

O
Osier Yang 已提交
9224
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238

    /* 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)
9239
            goto cleanup;
9240 9241 9242 9243 9244 9245 9246

        ret = 0;
        goto cleanup;
    }

    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
    if (NS_FAILED(rc)) {
9247 9248
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of domains, rc=%08x"), (unsigned)rc);
9249 9250 9251 9252 9253
        goto cleanup;
    }

    if (domains &&
        VIR_ALLOC_N(doms, machines.count + 1) < 0)
9254
        goto cleanup;
9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271

    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 已提交
9272
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
9273 9274 9275 9276 9277
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
                    continue;

                /* filter by snapshot existence */
O
Osier Yang 已提交
9278
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
9279 9280
                    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
                    if (NS_FAILED(rc)) {
9281
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9282
                                       _("could not get snapshot count for listed domains"));
9283 9284 9285 9286 9287 9288 9289 9290 9291 9292
                        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 已提交
9293
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358
                    !((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


9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382
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();
}

9383

9384 9385 9386 9387
/**
 * Function Tables
 */

9388
virDriver NAME(Driver) = {
9389 9390
    .no = VIR_DRV_VBOX,
    .name = "VBOX",
9391 9392 9393
    .connectOpen = vboxConnectOpen, /* 0.6.3 */
    .connectClose = vboxConnectClose, /* 0.6.3 */
    .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
9394
    .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
9395
    .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
9396
    .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */
9397 9398 9399 9400
    .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
    .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
    .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
    .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
9401 9402 9403 9404 9405 9406 9407
    .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 */
9408
    .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
9409 9410
    .domainReboot = vboxDomainReboot, /* 0.6.3 */
    .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
9411
    .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
9412 9413 9414 9415 9416 9417 9418 9419 9420 9421
    .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 */
9422 9423
    .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
    .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
9424 9425 9426 9427
    .domainCreate = vboxDomainCreate, /* 0.6.3 */
    .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
    .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
9428
    .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
9429 9430 9431 9432 9433
    .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 */
9434 9435
    .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */
9436
#if VBOX_API_VERSION >= 4000
9437
    .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
9438
#endif
9439
#if VBOX_API_VERSION > 2002 && VBOX_API_VERSION < 4000
9440 9441
    .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */
9442
#endif
9443 9444
    .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
9445 9446 9447
    .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
9448
#if VBOX_API_VERSION > 2002 && VBOX_API_VERSION < 4000
9449 9450
    .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */
9451
#endif
9452 9453 9454 9455 9456 9457
    .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 */
9458
    .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
9459
    .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
9460 9461
    .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
9462 9463
    .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
9464
    .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
9465
};
9466 9467 9468

virNetworkDriver NAME(NetworkDriver) = {
    "VBOX",
9469 9470
    .networkOpen = vboxNetworkOpen, /* 0.6.4 */
    .networkClose = vboxNetworkClose, /* 0.6.4 */
9471 9472 9473 9474
    .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */
    .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */
    .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */
    .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */
9475 9476 9477 9478 9479 9480 9481 9482
    .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 */
9483
};
9484 9485 9486

virStorageDriver NAME(StorageDriver) = {
    .name               = "VBOX",
9487 9488
    .storageOpen = vboxStorageOpen, /* 0.7.1 */
    .storageClose = vboxStorageClose, /* 0.7.1 */
9489 9490
    .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */
    .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */
9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502
    .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 */
9503
};