~ubuntu-branches/ubuntu/quantal/virtualbox/quantal

« back to all changes in this revision

Viewing changes to .pc/36-tarball-respin.patch/src/VBox/Main/src-server/HostImpl.cpp

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2012-04-05 12:41:55 UTC
  • mfrom: (3.1.12 sid)
  • Revision ID: package-import@ubuntu.com-20120405124155-i7b39tv5ddwhubbe
Tags: 4.1.12-dfsg-2
* Upstream has replaced the 4.1.12 tarball with a new one that fixes a
  crash when creating host only interfaces. (Closes: #667460)
  - Add 36-tarball-respin.patch which contains the diff between the old
    and the new tarball.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: HostImpl.cpp $ */
 
2
/** @file
 
3
 * VirtualBox COM class implementation: Host
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2011 Oracle Corporation
 
8
 *
 
9
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
10
 * available from http://www.virtualbox.org. This file is free software;
 
11
 * you can redistribute it and/or modify it under the terms of the GNU
 
12
 * General Public License (GPL) as published by the Free Software
 
13
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
14
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
15
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 */
 
17
 
 
18
#define __STDC_LIMIT_MACROS
 
19
#define __STDC_CONSTANT_MACROS
 
20
 
 
21
// for some reason Windows burns in sdk\...\winsock.h if this isn't included first
 
22
#include "VBox/com/ptr.h"
 
23
 
 
24
#include "HostImpl.h"
 
25
 
 
26
#ifdef VBOX_WITH_USB
 
27
# include "HostUSBDeviceImpl.h"
 
28
# include "USBDeviceFilterImpl.h"
 
29
# include "USBProxyService.h"
 
30
#endif // VBOX_WITH_USB
 
31
 
 
32
#include "HostNetworkInterfaceImpl.h"
 
33
#include "MachineImpl.h"
 
34
#include "AutoCaller.h"
 
35
#include "Logging.h"
 
36
#include "Performance.h"
 
37
 
 
38
#include "MediumImpl.h"
 
39
#include "HostPower.h"
 
40
 
 
41
#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
 
42
# include <HostHardwareLinux.h>
 
43
#endif
 
44
 
 
45
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
 
46
# include <set>
 
47
#endif
 
48
 
 
49
#ifdef VBOX_WITH_RESOURCE_USAGE_API
 
50
# include "PerformanceImpl.h"
 
51
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
 
52
 
 
53
#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
 
54
# include <VBox/VBoxNetCfg-win.h>
 
55
#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
 
56
 
 
57
#ifdef RT_OS_LINUX
 
58
# include <sys/ioctl.h>
 
59
# include <errno.h>
 
60
# include <net/if.h>
 
61
# include <net/if_arp.h>
 
62
#endif /* RT_OS_LINUX */
 
63
 
 
64
#ifdef RT_OS_SOLARIS
 
65
# include <fcntl.h>
 
66
# include <unistd.h>
 
67
# include <stropts.h>
 
68
# include <errno.h>
 
69
# include <limits.h>
 
70
# include <stdio.h>
 
71
# include <libdevinfo.h>
 
72
# include <sys/mkdev.h>
 
73
# include <sys/scsi/generic/inquiry.h>
 
74
# include <net/if.h>
 
75
# include <sys/socket.h>
 
76
# include <sys/sockio.h>
 
77
# include <net/if_arp.h>
 
78
# include <net/if.h>
 
79
# include <sys/types.h>
 
80
# include <sys/stat.h>
 
81
# include <sys/cdio.h>
 
82
# include <sys/dkio.h>
 
83
# include <sys/mnttab.h>
 
84
# include <sys/mntent.h>
 
85
/* Dynamic loading of libhal on Solaris hosts */
 
86
# ifdef VBOX_USE_LIBHAL
 
87
#  include "vbox-libhal.h"
 
88
extern "C" char *getfullrawname(char *);
 
89
# endif
 
90
# include "solaris/DynLoadLibSolaris.h"
 
91
 
 
92
/**
 
93
 * Solaris DVD drive list as returned by getDVDInfoFromDevTree().
 
94
 */
 
95
typedef struct SOLARISDVD
 
96
{
 
97
    struct SOLARISDVD *pNext;
 
98
    char szDescription[512];
 
99
    char szRawDiskPath[PATH_MAX];
 
100
} SOLARISDVD;
 
101
/** Pointer to a Solaris DVD descriptor. */
 
102
typedef SOLARISDVD *PSOLARISDVD;
 
103
 
 
104
#endif /* RT_OS_SOLARIS */
 
105
 
 
106
#ifdef RT_OS_WINDOWS
 
107
# define _WIN32_DCOM
 
108
# include <windows.h>
 
109
# include <shellapi.h>
 
110
# define INITGUID
 
111
# include <guiddef.h>
 
112
# include <devguid.h>
 
113
# include <objbase.h>
 
114
//# include <setupapi.h>
 
115
# include <shlobj.h>
 
116
# include <cfgmgr32.h>
 
117
 
 
118
#endif /* RT_OS_WINDOWS */
 
119
 
 
120
#ifdef RT_OS_DARWIN
 
121
# include "darwin/iokit.h"
 
122
#endif
 
123
 
 
124
#ifdef VBOX_WITH_CROGL
 
125
extern bool is3DAccelerationSupported();
 
126
#endif /* VBOX_WITH_CROGL */
 
127
 
 
128
#include <iprt/asm-amd64-x86.h>
 
129
#include <iprt/string.h>
 
130
#include <iprt/mp.h>
 
131
#include <iprt/time.h>
 
132
#include <iprt/param.h>
 
133
#include <iprt/env.h>
 
134
#include <iprt/mem.h>
 
135
#include <iprt/system.h>
 
136
#ifdef RT_OS_SOLARIS
 
137
# include <iprt/path.h>
 
138
# include <iprt/ctype.h>
 
139
#endif
 
140
#ifdef VBOX_WITH_HOSTNETIF_API
 
141
# include "netif.h"
 
142
#endif
 
143
 
 
144
/* XXX Solaris: definitions in /usr/include/sys/regset.h clash with hwacc_svm.h */
 
145
#undef DS
 
146
#undef ES
 
147
#undef CS
 
148
#undef SS
 
149
#undef FS
 
150
#undef GS
 
151
 
 
152
#include <VBox/usb.h>
 
153
#include <VBox/vmm/hwacc_svm.h>
 
154
#include <VBox/err.h>
 
155
#include <VBox/settings.h>
 
156
#include <VBox/sup.h>
 
157
#include <iprt/x86.h>
 
158
 
 
159
#include "VBox/com/MultiResult.h"
 
160
 
 
161
#include <stdio.h>
 
162
 
 
163
#include <algorithm>
 
164
 
 
165
////////////////////////////////////////////////////////////////////////////////
 
166
//
 
167
// Host private data definition
 
168
//
 
169
////////////////////////////////////////////////////////////////////////////////
 
170
 
 
171
struct Host::Data
 
172
{
 
173
    Data()
 
174
        :
 
175
#ifdef VBOX_WITH_USB
 
176
          usbListsLock(LOCKCLASS_USBLIST),
 
177
#endif
 
178
          drivesLock(LOCKCLASS_LISTOFMEDIA),
 
179
          fDVDDrivesListBuilt(false),
 
180
          fFloppyDrivesListBuilt(false)
 
181
    {};
 
182
 
 
183
    VirtualBox              *pParent;
 
184
 
 
185
#ifdef VBOX_WITH_USB
 
186
    WriteLockHandle         usbListsLock;               // protects the below two lists
 
187
 
 
188
    USBDeviceFilterList     llChildren;                 // all USB device filters
 
189
    USBDeviceFilterList     llUSBDeviceFilters;         // USB device filters in use by the USB proxy service
 
190
 
 
191
    /** Pointer to the USBProxyService object. */
 
192
    USBProxyService         *pUSBProxyService;
 
193
#endif /* VBOX_WITH_USB */
 
194
 
 
195
    // list of host drives; lazily created by getDVDDrives() and getFloppyDrives()
 
196
    WriteLockHandle         drivesLock;                 // protects the below two lists and the bools
 
197
    MediaList               llDVDDrives,
 
198
                            llFloppyDrives;
 
199
    bool                    fDVDDrivesListBuilt,
 
200
                            fFloppyDrivesListBuilt;
 
201
 
 
202
#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
 
203
    /** Object with information about host drives */
 
204
    VBoxMainDriveInfo       hostDrives;
 
205
#endif
 
206
    /* Features that can be queried with GetProcessorFeature */
 
207
    BOOL                    fVTSupported,
 
208
                            fLongModeSupported,
 
209
                            fPAESupported,
 
210
                            fNestedPagingSupported;
 
211
 
 
212
    /* 3D hardware acceleration supported? */
 
213
    BOOL                    f3DAccelerationSupported;
 
214
 
 
215
    HostPowerService        *pHostPowerService;
 
216
};
 
217
 
 
218
 
 
219
////////////////////////////////////////////////////////////////////////////////
 
220
//
 
221
// Constructor / destructor
 
222
//
 
223
////////////////////////////////////////////////////////////////////////////////
 
224
 
 
225
HRESULT Host::FinalConstruct()
 
226
{
 
227
    return BaseFinalConstruct();
 
228
}
 
229
 
 
230
void Host::FinalRelease()
 
231
{
 
232
    uninit();
 
233
    BaseFinalRelease();
 
234
}
 
235
 
 
236
/**
 
237
 * Initializes the host object.
 
238
 *
 
239
 * @param aParent   VirtualBox parent object.
 
240
 */
 
241
HRESULT Host::init(VirtualBox *aParent)
 
242
{
 
243
    HRESULT hrc;
 
244
    LogFlowThisFunc(("aParent=%p\n", aParent));
 
245
 
 
246
    /* Enclose the state transition NotReady->InInit->Ready */
 
247
    AutoInitSpan autoInitSpan(this);
 
248
    AssertReturn(autoInitSpan.isOk(), E_FAIL);
 
249
 
 
250
    m = new Data();
 
251
 
 
252
    m->pParent = aParent;
 
253
 
 
254
#ifdef VBOX_WITH_USB
 
255
    /*
 
256
     * Create and initialize the USB Proxy Service.
 
257
     */
 
258
# if defined (RT_OS_DARWIN)
 
259
    m->pUSBProxyService = new USBProxyServiceDarwin(this);
 
260
# elif defined (RT_OS_LINUX)
 
261
    m->pUSBProxyService = new USBProxyServiceLinux(this);
 
262
# elif defined (RT_OS_OS2)
 
263
    m->pUSBProxyService = new USBProxyServiceOs2(this);
 
264
# elif defined (RT_OS_SOLARIS)
 
265
    m->pUSBProxyService = new USBProxyServiceSolaris(this);
 
266
# elif defined (RT_OS_WINDOWS)
 
267
    m->pUSBProxyService = new USBProxyServiceWindows(this);
 
268
# elif defined (RT_OS_FREEBSD)
 
269
    m->pUSBProxyService = new USBProxyServiceFreeBSD(this);
 
270
# else
 
271
    m->pUSBProxyService = new USBProxyService(this);
 
272
# endif
 
273
    hrc = m->pUSBProxyService->init();
 
274
    AssertComRCReturn(hrc, hrc);
 
275
#endif /* VBOX_WITH_USB */
 
276
 
 
277
#ifdef VBOX_WITH_RESOURCE_USAGE_API
 
278
    registerMetrics(aParent->performanceCollector());
 
279
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
 
280
 
 
281
#if defined (RT_OS_WINDOWS)
 
282
    m->pHostPowerService = new HostPowerServiceWin(m->pParent);
 
283
#elif defined (RT_OS_DARWIN)
 
284
    m->pHostPowerService = new HostPowerServiceDarwin(m->pParent);
 
285
#else
 
286
    m->pHostPowerService = new HostPowerService(m->pParent);
 
287
#endif
 
288
 
 
289
    /* Cache the features reported by GetProcessorFeature. */
 
290
    m->fVTSupported = false;
 
291
    m->fLongModeSupported = false;
 
292
    m->fPAESupported = false;
 
293
    m->fNestedPagingSupported = false;
 
294
 
 
295
    if (ASMHasCpuId())
 
296
    {
 
297
        uint32_t u32FeaturesECX;
 
298
        uint32_t u32Dummy;
 
299
        uint32_t u32FeaturesEDX;
 
300
        uint32_t u32VendorEBX, u32VendorECX, u32VendorEDX, u32AMDFeatureEDX, u32AMDFeatureECX;
 
301
 
 
302
        ASMCpuId(0, &u32Dummy, &u32VendorEBX, &u32VendorECX, &u32VendorEDX);
 
303
        ASMCpuId(1, &u32Dummy, &u32Dummy, &u32FeaturesECX, &u32FeaturesEDX);
 
304
        /* Query AMD features. */
 
305
        ASMCpuId(0x80000001, &u32Dummy, &u32Dummy, &u32AMDFeatureECX, &u32AMDFeatureEDX);
 
306
 
 
307
        m->fLongModeSupported = !!(u32AMDFeatureEDX & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE);
 
308
        m->fPAESupported      = !!(u32FeaturesEDX & X86_CPUID_FEATURE_EDX_PAE);
 
309
 
 
310
        if (    u32VendorEBX == X86_CPUID_VENDOR_INTEL_EBX
 
311
            &&  u32VendorECX == X86_CPUID_VENDOR_INTEL_ECX
 
312
            &&  u32VendorEDX == X86_CPUID_VENDOR_INTEL_EDX
 
313
           )
 
314
        {
 
315
            if (    (u32FeaturesECX & X86_CPUID_FEATURE_ECX_VMX)
 
316
                 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
 
317
                 && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
 
318
               )
 
319
            {
 
320
                int rc = SUPR3QueryVTxSupported();
 
321
                if (RT_SUCCESS(rc))
 
322
                    m->fVTSupported = true;
 
323
            }
 
324
        }
 
325
        else
 
326
        if (    u32VendorEBX == X86_CPUID_VENDOR_AMD_EBX
 
327
            &&  u32VendorECX == X86_CPUID_VENDOR_AMD_ECX
 
328
            &&  u32VendorEDX == X86_CPUID_VENDOR_AMD_EDX
 
329
           )
 
330
        {
 
331
            if (   (u32AMDFeatureECX & X86_CPUID_AMD_FEATURE_ECX_SVM)
 
332
                && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_MSR)
 
333
                && (u32FeaturesEDX & X86_CPUID_FEATURE_EDX_FXSR)
 
334
               )
 
335
            {
 
336
                uint32_t u32SVMFeatureEDX;
 
337
 
 
338
                m->fVTSupported = true;
 
339
 
 
340
                /* Query AMD features. */
 
341
                ASMCpuId(0x8000000A, &u32Dummy, &u32Dummy, &u32Dummy, &u32SVMFeatureEDX);
 
342
                if (u32SVMFeatureEDX & AMD_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
 
343
                    m->fNestedPagingSupported = true;
 
344
            }
 
345
        }
 
346
    }
 
347
 
 
348
#if 0 /* needs testing */
 
349
    if (m->fVTSupported)
 
350
    {
 
351
        uint32_t u32Caps = 0;
 
352
 
 
353
        int rc = SUPR3QueryVTCaps(&u32Caps);
 
354
        if (RT_SUCCESS(rc))
 
355
        {
 
356
            if (u32Caps & SUPVTCAPS_NESTED_PAGING)
 
357
                m->fNestedPagingSupported = true;
 
358
        }
 
359
        /* else @todo; report BIOS trouble in some way. */
 
360
    }
 
361
#endif
 
362
 
 
363
    /* Test for 3D hardware acceleration support */
 
364
    m->f3DAccelerationSupported = false;
 
365
 
 
366
#ifdef VBOX_WITH_CROGL
 
367
    m->f3DAccelerationSupported = is3DAccelerationSupported();
 
368
#endif /* VBOX_WITH_CROGL */
 
369
 
 
370
#if defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
 
371
    /* Extract the list of configured host-only interfaces */
 
372
    std::set<Utf8Str> aConfiguredNames;
 
373
    SafeArray<BSTR> aGlobalExtraDataKeys;
 
374
    hrc = aParent->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
 
375
    AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
 
376
    for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
 
377
    {
 
378
        Utf8Str strKey = aGlobalExtraDataKeys[i];
 
379
 
 
380
        if (!strKey.startsWith("HostOnly/vboxnet"))
 
381
            continue;
 
382
 
 
383
        size_t pos = strKey.find("/", sizeof("HostOnly/vboxnet"));
 
384
        if (pos != Utf8Str::npos)
 
385
            aConfiguredNames.insert(strKey.substr(sizeof("HostOnly"),
 
386
                                                  pos - sizeof("HostOnly")));
 
387
    }
 
388
 
 
389
    for (std::set<Utf8Str>::const_iterator it = aConfiguredNames.begin();
 
390
         it != aConfiguredNames.end();
 
391
         ++it)
 
392
    {
 
393
        ComPtr<IHostNetworkInterface> hif;
 
394
        ComPtr<IProgress> progress;
 
395
 
 
396
        int r = NetIfCreateHostOnlyNetworkInterface(m->pParent,
 
397
                                                    hif.asOutParam(),
 
398
                                                    progress.asOutParam(),
 
399
                                                    it->c_str());
 
400
        if (RT_FAILURE(r))
 
401
            return E_FAIL;
 
402
    }
 
403
 
 
404
#endif /* defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) */
 
405
 
 
406
    /* Confirm a successful initialization */
 
407
    autoInitSpan.setSucceeded();
 
408
 
 
409
    return S_OK;
 
410
}
 
411
 
 
412
/**
 
413
 *  Uninitializes the host object and sets the ready flag to FALSE.
 
414
 *  Called either from FinalRelease() or by the parent when it gets destroyed.
 
415
 */
 
416
void Host::uninit()
 
417
{
 
418
    LogFlowThisFunc(("\n"));
 
419
 
 
420
    /* Enclose the state transition Ready->InUninit->NotReady */
 
421
    AutoUninitSpan autoUninitSpan(this);
 
422
    if (autoUninitSpan.uninitDone())
 
423
        return;
 
424
 
 
425
#ifdef VBOX_WITH_RESOURCE_USAGE_API
 
426
    unregisterMetrics (m->pParent->performanceCollector());
 
427
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
 
428
 
 
429
#ifdef VBOX_WITH_USB
 
430
    /* wait for USB proxy service to terminate before we uninit all USB
 
431
     * devices */
 
432
    LogFlowThisFunc(("Stopping USB proxy service...\n"));
 
433
    delete m->pUSBProxyService;
 
434
    m->pUSBProxyService = NULL;
 
435
    LogFlowThisFunc(("Done stopping USB proxy service.\n"));
 
436
#endif
 
437
 
 
438
    delete m->pHostPowerService;
 
439
 
 
440
#ifdef VBOX_WITH_USB
 
441
    /* uninit all USB device filters still referenced by clients
 
442
     * Note! HostUSBDeviceFilter::uninit() will modify llChildren. */
 
443
    while (!m->llChildren.empty())
 
444
    {
 
445
        ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
 
446
        pChild->uninit();
 
447
    }
 
448
 
 
449
    m->llUSBDeviceFilters.clear();
 
450
#endif
 
451
 
 
452
    delete m;
 
453
    m = NULL;
 
454
}
 
455
 
 
456
////////////////////////////////////////////////////////////////////////////////
 
457
//
 
458
// ISnapshot public methods
 
459
//
 
460
////////////////////////////////////////////////////////////////////////////////
 
461
 
 
462
/**
 
463
 * Returns a list of host DVD drives.
 
464
 *
 
465
 * @returns COM status code
 
466
 * @param drives address of result pointer
 
467
 */
 
468
STDMETHODIMP Host::COMGETTER(DVDDrives)(ComSafeArrayOut(IMedium *, aDrives))
 
469
{
 
470
    CheckComArgOutSafeArrayPointerValid(aDrives);
 
471
 
 
472
    AutoCaller autoCaller(this);
 
473
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
474
 
 
475
    AutoWriteLock alock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
 
476
 
 
477
    MediaList *pList;
 
478
    HRESULT rc = getDrives(DeviceType_DVD, true /* fRefresh */, pList);
 
479
    if (SUCCEEDED(rc))
 
480
    {
 
481
        SafeIfaceArray<IMedium> array(*pList);
 
482
        array.detachTo(ComSafeArrayOutArg(aDrives));
 
483
    }
 
484
 
 
485
    return rc;
 
486
}
 
487
 
 
488
/**
 
489
 * Returns a list of host floppy drives.
 
490
 *
 
491
 * @returns COM status code
 
492
 * @param drives address of result pointer
 
493
 */
 
494
STDMETHODIMP Host::COMGETTER(FloppyDrives)(ComSafeArrayOut(IMedium *, aDrives))
 
495
{
 
496
    CheckComArgOutPointerValid(aDrives);
 
497
 
 
498
    AutoCaller autoCaller(this);
 
499
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
500
 
 
501
    AutoWriteLock alock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
 
502
 
 
503
    MediaList *pList;
 
504
    HRESULT rc = getDrives(DeviceType_Floppy, true /* fRefresh */, pList);
 
505
    if (SUCCEEDED(rc))
 
506
    {
 
507
        SafeIfaceArray<IMedium> collection(*pList);
 
508
        collection.detachTo(ComSafeArrayOutArg(aDrives));
 
509
    }
 
510
 
 
511
    return rc;
 
512
}
 
513
 
 
514
 
 
515
#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
 
516
# define VBOX_APP_NAME L"VirtualBox"
 
517
 
 
518
static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
 
519
                                  INetCfgComponent *pncc)
 
520
{
 
521
    LPWSTR              lpszName;
 
522
    GUID                IfGuid;
 
523
    HRESULT hr;
 
524
    int rc = VERR_GENERAL_FAILURE;
 
525
 
 
526
    hr = pncc->GetDisplayName( &lpszName );
 
527
    Assert(hr == S_OK);
 
528
    if (hr == S_OK)
 
529
    {
 
530
        Bstr name((CBSTR)lpszName);
 
531
 
 
532
        hr = pncc->GetInstanceGuid(&IfGuid);
 
533
        Assert(hr == S_OK);
 
534
        if (hr == S_OK)
 
535
        {
 
536
            /* create a new object and add it to the list */
 
537
            ComObjPtr<HostNetworkInterface> iface;
 
538
            iface.createObject();
 
539
            /* remove the curly bracket at the end */
 
540
            if (SUCCEEDED(iface->init (name, Guid (IfGuid), HostNetworkInterfaceType_Bridged)))
 
541
            {
 
542
//                iface->setVirtualBox(m->pParent);
 
543
                pPist->push_back(iface);
 
544
                rc = VINF_SUCCESS;
 
545
            }
 
546
            else
 
547
            {
 
548
                Assert(0);
 
549
            }
 
550
        }
 
551
        CoTaskMemFree(lpszName);
 
552
    }
 
553
 
 
554
    return rc;
 
555
}
 
556
#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
 
557
 
 
558
/**
 
559
 * Returns a list of host network interfaces.
 
560
 *
 
561
 * @returns COM status code
 
562
 * @param drives address of result pointer
 
563
 */
 
564
STDMETHODIMP Host::COMGETTER(NetworkInterfaces)(ComSafeArrayOut(IHostNetworkInterface*, aNetworkInterfaces))
 
565
{
 
566
#if defined(RT_OS_WINDOWS) ||  defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
 
567
    if (ComSafeArrayOutIsNull(aNetworkInterfaces))
 
568
        return E_POINTER;
 
569
 
 
570
    AutoCaller autoCaller(this);
 
571
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
572
 
 
573
    std::list<ComObjPtr<HostNetworkInterface> > list;
 
574
 
 
575
# ifdef VBOX_WITH_HOSTNETIF_API
 
576
    int rc = NetIfList(list);
 
577
    if (rc)
 
578
    {
 
579
        Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
 
580
    }
 
581
# else
 
582
 
 
583
#  if defined(RT_OS_DARWIN)
 
584
    PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
 
585
    while (pEtherNICs)
 
586
    {
 
587
        ComObjPtr<HostNetworkInterface> IfObj;
 
588
        IfObj.createObject();
 
589
        if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
 
590
            list.push_back(IfObj);
 
591
 
 
592
        /* next, free current */
 
593
        void *pvFree = pEtherNICs;
 
594
        pEtherNICs = pEtherNICs->pNext;
 
595
        RTMemFree(pvFree);
 
596
    }
 
597
 
 
598
#  elif defined RT_OS_WINDOWS
 
599
#   ifndef VBOX_WITH_NETFLT
 
600
    hr = E_NOTIMPL;
 
601
#   else /* #  if defined VBOX_WITH_NETFLT */
 
602
    INetCfg              *pNc;
 
603
    INetCfgComponent     *pMpNcc;
 
604
    INetCfgComponent     *pTcpIpNcc;
 
605
    LPWSTR               lpszApp;
 
606
    HRESULT              hr;
 
607
    IEnumNetCfgBindingPath      *pEnumBp;
 
608
    INetCfgBindingPath          *pBp;
 
609
    IEnumNetCfgBindingInterface *pEnumBi;
 
610
    INetCfgBindingInterface *pBi;
 
611
 
 
612
    /* we are using the INetCfg API for getting the list of miniports */
 
613
    hr = VBoxNetCfgWinQueryINetCfg( FALSE,
 
614
                       VBOX_APP_NAME,
 
615
                       &pNc,
 
616
                       &lpszApp );
 
617
    Assert(hr == S_OK);
 
618
    if (hr == S_OK)
 
619
    {
 
620
#    ifdef VBOX_NETFLT_ONDEMAND_BIND
 
621
        /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
 
622
        hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
 
623
#    else
 
624
        /* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
 
625
        hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
 
626
#     ifndef VBOX_WITH_HARDENING
 
627
        if (hr != S_OK)
 
628
        {
 
629
            /* TODO: try to install the netflt from here */
 
630
        }
 
631
#     endif
 
632
 
 
633
#    endif
 
634
 
 
635
        if (hr == S_OK)
 
636
        {
 
637
            hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
 
638
            Assert(hr == S_OK);
 
639
            if ( hr == S_OK )
 
640
            {
 
641
                hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
 
642
                Assert(hr == S_OK || hr == S_FALSE);
 
643
                while( hr == S_OK )
 
644
                {
 
645
                    /* S_OK == enabled, S_FALSE == disabled */
 
646
                    if (pBp->IsEnabled() == S_OK)
 
647
                    {
 
648
                        hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
 
649
                        Assert(hr == S_OK);
 
650
                        if ( hr == S_OK )
 
651
                        {
 
652
                            hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
 
653
                            Assert(hr == S_OK);
 
654
                            while(hr == S_OK)
 
655
                            {
 
656
                                hr = pBi->GetLowerComponent( &pMpNcc );
 
657
                                Assert(hr == S_OK);
 
658
                                if (hr == S_OK)
 
659
                                {
 
660
                                    ULONG uComponentStatus;
 
661
                                    hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
 
662
                                    Assert(hr == S_OK);
 
663
                                    if (hr == S_OK)
 
664
                                    {
 
665
                                        if (uComponentStatus == 0)
 
666
                                        {
 
667
                                            vboxNetWinAddComponent(&list, pMpNcc);
 
668
                                        }
 
669
                                    }
 
670
                                    VBoxNetCfgWinReleaseRef( pMpNcc );
 
671
                                }
 
672
                                VBoxNetCfgWinReleaseRef(pBi);
 
673
 
 
674
                                hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
 
675
                            }
 
676
                            VBoxNetCfgWinReleaseRef(pEnumBi);
 
677
                        }
 
678
                    }
 
679
                    VBoxNetCfgWinReleaseRef(pBp);
 
680
 
 
681
                    hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
 
682
                }
 
683
                VBoxNetCfgWinReleaseRef(pEnumBp);
 
684
            }
 
685
            VBoxNetCfgWinReleaseRef(pTcpIpNcc);
 
686
        }
 
687
        else
 
688
        {
 
689
            LogRel(("failed to get the sun_VBoxNetFlt component, error (0x%x)", hr));
 
690
        }
 
691
 
 
692
        VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
 
693
    }
 
694
#   endif /* #  if defined VBOX_WITH_NETFLT */
 
695
 
 
696
 
 
697
#  elif defined RT_OS_LINUX
 
698
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
 
699
    if (sock >= 0)
 
700
    {
 
701
        char pBuffer[2048];
 
702
        struct ifconf ifConf;
 
703
        ifConf.ifc_len = sizeof(pBuffer);
 
704
        ifConf.ifc_buf = pBuffer;
 
705
        if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
 
706
        {
 
707
            for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
 
708
            {
 
709
                if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
 
710
                {
 
711
                    if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
 
712
                    {
 
713
                        RTUUID uuid;
 
714
                        Assert(sizeof(uuid) <= sizeof(*pReq));
 
715
                        memcpy(&uuid, pReq, sizeof(uuid));
 
716
 
 
717
                        ComObjPtr<HostNetworkInterface> IfObj;
 
718
                        IfObj.createObject();
 
719
                        if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
 
720
                            list.push_back(IfObj);
 
721
                    }
 
722
                }
 
723
            }
 
724
        }
 
725
        close(sock);
 
726
    }
 
727
#  endif /* RT_OS_LINUX */
 
728
# endif
 
729
 
 
730
    std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
 
731
    for (it = list.begin(); it != list.end(); ++it)
 
732
    {
 
733
        (*it)->setVirtualBox(m->pParent);
 
734
    }
 
735
 
 
736
    SafeIfaceArray<IHostNetworkInterface> networkInterfaces (list);
 
737
    networkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
 
738
 
 
739
    return S_OK;
 
740
 
 
741
#else
 
742
    /* Not implemented / supported on this platform. */
 
743
    ReturnComNotImplemented();
 
744
#endif
 
745
}
 
746
 
 
747
STDMETHODIMP Host::COMGETTER(USBDevices)(ComSafeArrayOut(IHostUSBDevice*, aUSBDevices))
 
748
{
 
749
#ifdef VBOX_WITH_USB
 
750
    CheckComArgOutSafeArrayPointerValid(aUSBDevices);
 
751
 
 
752
    AutoCaller autoCaller(this);
 
753
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
754
 
 
755
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
756
 
 
757
    HRESULT rc = checkUSBProxyService();
 
758
    if (FAILED(rc)) return rc;
 
759
 
 
760
    return m->pUSBProxyService->getDeviceCollection(ComSafeArrayOutArg(aUSBDevices));
 
761
 
 
762
#else
 
763
    /* Note: The GUI depends on this method returning E_NOTIMPL with no
 
764
     * extended error info to indicate that USB is simply not available
 
765
     * (w/o treating it as a failure), for example, as in OSE. */
 
766
    NOREF(aUSBDevices);
 
767
# ifndef RT_OS_WINDOWS
 
768
    NOREF(aUSBDevicesSize);
 
769
# endif
 
770
    ReturnComNotImplemented();
 
771
#endif
 
772
}
 
773
 
 
774
STDMETHODIMP Host::COMGETTER(USBDeviceFilters)(ComSafeArrayOut(IHostUSBDeviceFilter*, aUSBDeviceFilters))
 
775
{
 
776
#ifdef VBOX_WITH_USB
 
777
    CheckComArgOutSafeArrayPointerValid(aUSBDeviceFilters);
 
778
 
 
779
    AutoCaller autoCaller(this);
 
780
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
781
 
 
782
    AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
 
783
 
 
784
    HRESULT rc = checkUSBProxyService();
 
785
    if (FAILED(rc)) return rc;
 
786
 
 
787
    SafeIfaceArray<IHostUSBDeviceFilter> collection(m->llUSBDeviceFilters);
 
788
    collection.detachTo(ComSafeArrayOutArg(aUSBDeviceFilters));
 
789
 
 
790
    return rc;
 
791
#else
 
792
    /* Note: The GUI depends on this method returning E_NOTIMPL with no
 
793
     * extended error info to indicate that USB is simply not available
 
794
     * (w/o treating it as a failure), for example, as in OSE. */
 
795
    NOREF(aUSBDeviceFilters);
 
796
# ifndef RT_OS_WINDOWS
 
797
    NOREF(aUSBDeviceFiltersSize);
 
798
# endif
 
799
    ReturnComNotImplemented();
 
800
#endif
 
801
}
 
802
 
 
803
/**
 
804
 * Returns the number of installed logical processors
 
805
 *
 
806
 * @returns COM status code
 
807
 * @param   count address of result variable
 
808
 */
 
809
STDMETHODIMP Host::COMGETTER(ProcessorCount)(ULONG *aCount)
 
810
{
 
811
    CheckComArgOutPointerValid(aCount);
 
812
    // no locking required
 
813
 
 
814
    *aCount = RTMpGetPresentCount();
 
815
    return S_OK;
 
816
}
 
817
 
 
818
/**
 
819
 * Returns the number of online logical processors
 
820
 *
 
821
 * @returns COM status code
 
822
 * @param   count address of result variable
 
823
 */
 
824
STDMETHODIMP Host::COMGETTER(ProcessorOnlineCount)(ULONG *aCount)
 
825
{
 
826
    CheckComArgOutPointerValid(aCount);
 
827
    // no locking required
 
828
 
 
829
    *aCount = RTMpGetOnlineCount();
 
830
    return S_OK;
 
831
}
 
832
 
 
833
/**
 
834
 * Returns the number of installed physical processor cores.
 
835
 *
 
836
 * @returns COM status code
 
837
 * @param   count address of result variable
 
838
 */
 
839
STDMETHODIMP Host::COMGETTER(ProcessorCoreCount)(ULONG *aCount)
 
840
{
 
841
    CheckComArgOutPointerValid(aCount);
 
842
    // no locking required
 
843
 
 
844
    return E_NOTIMPL;
 
845
}
 
846
 
 
847
/**
 
848
 * Returns the (approximate) maximum speed of the given host CPU in MHz
 
849
 *
 
850
 * @returns COM status code
 
851
 * @param   cpu id to get info for.
 
852
 * @param   speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
 
853
 */
 
854
STDMETHODIMP Host::GetProcessorSpeed(ULONG aCpuId, ULONG *aSpeed)
 
855
{
 
856
    CheckComArgOutPointerValid(aSpeed);
 
857
    // no locking required
 
858
 
 
859
    *aSpeed = RTMpGetMaxFrequency(aCpuId);
 
860
    return S_OK;
 
861
}
 
862
 
 
863
/**
 
864
 * Returns a description string for the host CPU
 
865
 *
 
866
 * @returns COM status code
 
867
 * @param   cpu id to get info for.
 
868
 * @param   description address of result variable, empty string if not known or aCpuId is invalid.
 
869
 */
 
870
STDMETHODIMP Host::GetProcessorDescription(ULONG aCpuId, BSTR *aDescription)
 
871
{
 
872
    CheckComArgOutPointerValid(aDescription);
 
873
    // no locking required
 
874
 
 
875
    char szCPUModel[80];
 
876
    int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
 
877
    if (RT_FAILURE(vrc))
 
878
        return E_FAIL; /** @todo error reporting? */
 
879
    Bstr (szCPUModel).cloneTo(aDescription);
 
880
    return S_OK;
 
881
}
 
882
 
 
883
/**
 
884
 * Returns whether a host processor feature is supported or not
 
885
 *
 
886
 * @returns COM status code
 
887
 * @param   Feature to query.
 
888
 * @param   address of supported bool result variable
 
889
 */
 
890
STDMETHODIMP Host::GetProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
 
891
{
 
892
    CheckComArgOutPointerValid(aSupported);
 
893
    AutoCaller autoCaller(this);
 
894
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
895
 
 
896
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
897
 
 
898
    switch (aFeature)
 
899
    {
 
900
        case ProcessorFeature_HWVirtEx:
 
901
            *aSupported = m->fVTSupported;
 
902
            break;
 
903
 
 
904
        case ProcessorFeature_PAE:
 
905
            *aSupported = m->fPAESupported;
 
906
            break;
 
907
 
 
908
        case ProcessorFeature_LongMode:
 
909
            *aSupported = m->fLongModeSupported;
 
910
            break;
 
911
 
 
912
        case ProcessorFeature_NestedPaging:
 
913
            *aSupported = m->fNestedPagingSupported;
 
914
            break;
 
915
 
 
916
        default:
 
917
            ReturnComNotImplemented();
 
918
    }
 
919
    return S_OK;
 
920
}
 
921
 
 
922
/**
 
923
 * Returns the specific CPUID leaf.
 
924
 *
 
925
 * @returns COM status code
 
926
 * @param   aCpuId              The CPU number. Mostly ignored.
 
927
 * @param   aLeaf               The leaf number.
 
928
 * @param   aSubLeaf            The sub-leaf number.
 
929
 * @param   aValEAX             Where to return EAX.
 
930
 * @param   aValEBX             Where to return EBX.
 
931
 * @param   aValECX             Where to return ECX.
 
932
 * @param   aValEDX             Where to return EDX.
 
933
 */
 
934
STDMETHODIMP Host::GetProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
 
935
                                         ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
 
936
{
 
937
    CheckComArgOutPointerValid(aValEAX);
 
938
    CheckComArgOutPointerValid(aValEBX);
 
939
    CheckComArgOutPointerValid(aValECX);
 
940
    CheckComArgOutPointerValid(aValEDX);
 
941
    // no locking required
 
942
 
 
943
    /* Check that the CPU is online. */
 
944
    /** @todo later use RTMpOnSpecific. */
 
945
    if (!RTMpIsCpuOnline(aCpuId))
 
946
        return RTMpIsCpuPresent(aCpuId)
 
947
             ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
 
948
             : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
 
949
 
 
950
    uint32_t uEAX, uEBX, uECX, uEDX;
 
951
    ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
 
952
    *aValEAX = uEAX;
 
953
    *aValEBX = uEBX;
 
954
    *aValECX = uECX;
 
955
    *aValEDX = uEDX;
 
956
 
 
957
    return S_OK;
 
958
}
 
959
 
 
960
/**
 
961
 * Returns the amount of installed system memory in megabytes
 
962
 *
 
963
 * @returns COM status code
 
964
 * @param   size address of result variable
 
965
 */
 
966
STDMETHODIMP Host::COMGETTER(MemorySize)(ULONG *aSize)
 
967
{
 
968
    CheckComArgOutPointerValid(aSize);
 
969
    // no locking required
 
970
 
 
971
    /* @todo This is an ugly hack. There must be a function in IPRT for that. */
 
972
    pm::CollectorHAL *hal = pm::createHAL();
 
973
    if (!hal)
 
974
        return E_FAIL;
 
975
    ULONG tmp;
 
976
    int rc = hal->getHostMemoryUsage(aSize, &tmp, &tmp);
 
977
    *aSize /= 1024;
 
978
    delete hal;
 
979
    return rc;
 
980
}
 
981
 
 
982
/**
 
983
 * Returns the current system memory free space in megabytes
 
984
 *
 
985
 * @returns COM status code
 
986
 * @param   available address of result variable
 
987
 */
 
988
STDMETHODIMP Host::COMGETTER(MemoryAvailable)(ULONG *aAvailable)
 
989
{
 
990
    CheckComArgOutPointerValid(aAvailable);
 
991
    // no locking required
 
992
 
 
993
    /* @todo This is an ugly hack. There must be a function in IPRT for that. */
 
994
    pm::CollectorHAL *hal = pm::createHAL();
 
995
    if (!hal)
 
996
        return E_FAIL;
 
997
    ULONG tmp;
 
998
    int rc = hal->getHostMemoryUsage(&tmp, &tmp, aAvailable);
 
999
    *aAvailable /= 1024;
 
1000
    delete hal;
 
1001
    return rc;
 
1002
}
 
1003
 
 
1004
/**
 
1005
 * Returns the name string of the host operating system
 
1006
 *
 
1007
 * @returns COM status code
 
1008
 * @param   os address of result variable
 
1009
 */
 
1010
STDMETHODIMP Host::COMGETTER(OperatingSystem)(BSTR *aOs)
 
1011
{
 
1012
    CheckComArgOutPointerValid(aOs);
 
1013
    // no locking required
 
1014
 
 
1015
    char szOSName[80];
 
1016
    int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
 
1017
    if (RT_FAILURE(vrc))
 
1018
        return E_FAIL; /** @todo error reporting? */
 
1019
    Bstr (szOSName).cloneTo(aOs);
 
1020
    return S_OK;
 
1021
}
 
1022
 
 
1023
/**
 
1024
 * Returns the version string of the host operating system
 
1025
 *
 
1026
 * @returns COM status code
 
1027
 * @param   os address of result variable
 
1028
 */
 
1029
STDMETHODIMP Host::COMGETTER(OSVersion)(BSTR *aVersion)
 
1030
{
 
1031
    CheckComArgOutPointerValid(aVersion);
 
1032
    // no locking required
 
1033
 
 
1034
    /* Get the OS release. Reserve some buffer space for the service pack. */
 
1035
    char szOSRelease[128];
 
1036
    int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
 
1037
    if (RT_FAILURE(vrc))
 
1038
        return E_FAIL; /** @todo error reporting? */
 
1039
 
 
1040
    /* Append the service pack if present. */
 
1041
    char szOSServicePack[80];
 
1042
    vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
 
1043
    if (RT_FAILURE(vrc))
 
1044
    {
 
1045
        if (vrc != VERR_NOT_SUPPORTED)
 
1046
            return E_FAIL; /** @todo error reporting? */
 
1047
        szOSServicePack[0] = '\0';
 
1048
    }
 
1049
    if (szOSServicePack[0] != '\0')
 
1050
    {
 
1051
        char *psz = strchr(szOSRelease, '\0');
 
1052
        RTStrPrintf(psz, &szOSRelease[sizeof(szOSRelease)] - psz, "sp%s", szOSServicePack);
 
1053
    }
 
1054
 
 
1055
    Bstr(szOSRelease).cloneTo(aVersion);
 
1056
    return S_OK;
 
1057
}
 
1058
 
 
1059
/**
 
1060
 * Returns the current host time in milliseconds since 1970-01-01 UTC.
 
1061
 *
 
1062
 * @returns COM status code
 
1063
 * @param   time address of result variable
 
1064
 */
 
1065
STDMETHODIMP Host::COMGETTER(UTCTime)(LONG64 *aUTCTime)
 
1066
{
 
1067
    CheckComArgOutPointerValid(aUTCTime);
 
1068
    // no locking required
 
1069
 
 
1070
    RTTIMESPEC now;
 
1071
    *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
 
1072
 
 
1073
    return S_OK;
 
1074
}
 
1075
 
 
1076
STDMETHODIMP Host::COMGETTER(Acceleration3DAvailable)(BOOL *aSupported)
 
1077
{
 
1078
    CheckComArgOutPointerValid(aSupported);
 
1079
    AutoCaller autoCaller(this);
 
1080
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
1081
 
 
1082
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
1083
 
 
1084
    *aSupported = m->f3DAccelerationSupported;
 
1085
 
 
1086
    return S_OK;
 
1087
}
 
1088
 
 
1089
STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
 
1090
                                                  IProgress **aProgress)
 
1091
{
 
1092
    CheckComArgOutPointerValid(aHostNetworkInterface);
 
1093
    CheckComArgNotNull(*aHostNetworkInterface);
 
1094
    CheckComArgOutPointerValid(aProgress);
 
1095
 
 
1096
    AutoCaller autoCaller(this);
 
1097
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
1098
 
 
1099
#ifdef VBOX_WITH_HOSTNETIF_API
 
1100
    /* No need to lock anything. If there ever will - watch out, the function
 
1101
     * called below grabs the VirtualBox lock. */
 
1102
 
 
1103
    int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
 
1104
    if (RT_SUCCESS(r))
 
1105
    {
 
1106
#if !defined(RT_OS_WINDOWS)
 
1107
        Bstr tmpAddr, tmpMask, tmpName;
 
1108
        HRESULT hrc;
 
1109
        hrc = (*aHostNetworkInterface)->COMGETTER(Name)(tmpName.asOutParam());
 
1110
        ComAssertComRCRet(hrc, hrc);
 
1111
        hrc = (*aHostNetworkInterface)->COMGETTER(IPAddress)(tmpAddr.asOutParam());
 
1112
        ComAssertComRCRet(hrc, hrc);
 
1113
        hrc = (*aHostNetworkInterface)->COMGETTER(NetworkMask)(tmpMask.asOutParam());
 
1114
        ComAssertComRCRet(hrc, hrc);
 
1115
        /*
 
1116
         * We need to write the default IP address and mask to extra data now,
 
1117
         * so the interface gets re-created after vboxnetadp.ko reload.
 
1118
         * Note that we avoid calling EnableStaticIpConfig since it would
 
1119
         * change the address on host's interface as well and we want to
 
1120
         * postpone the change until VM actually starts.
 
1121
         */
 
1122
        hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
 
1123
                                               tmpName.raw()).raw(),
 
1124
                                       tmpAddr.raw());
 
1125
        ComAssertComRCRet(hrc, hrc);
 
1126
 
 
1127
        hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
 
1128
                                               tmpName.raw()).raw(),
 
1129
                                       tmpMask.raw());
 
1130
        ComAssertComRCRet(hrc, hrc);
 
1131
#endif
 
1132
        return S_OK;
 
1133
    }
 
1134
 
 
1135
    return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
 
1136
#else
 
1137
    return E_NOTIMPL;
 
1138
#endif
 
1139
}
 
1140
 
 
1141
STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
 
1142
                                                  IProgress **aProgress)
 
1143
{
 
1144
    CheckComArgOutPointerValid(aProgress);
 
1145
 
 
1146
    AutoCaller autoCaller(this);
 
1147
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
1148
 
 
1149
#ifdef VBOX_WITH_HOSTNETIF_API
 
1150
    /* No need to lock anything, the code below does not touch the state
 
1151
     * of the host object. If that ever changes then check for lock order
 
1152
     * violations with the called functions. */
 
1153
 
 
1154
    Bstr name;
 
1155
    HRESULT rc;
 
1156
 
 
1157
    /* first check whether an interface with the given name already exists */
 
1158
    {
 
1159
        ComPtr<IHostNetworkInterface> iface;
 
1160
        if (FAILED(FindHostNetworkInterfaceById(aId,
 
1161
                                                iface.asOutParam())))
 
1162
            return setError(VBOX_E_OBJECT_NOT_FOUND,
 
1163
                            tr("Host network interface with UUID {%RTuuid} does not exist"),
 
1164
                            Guid (aId).raw());
 
1165
        rc = iface->COMGETTER(Name)(name.asOutParam());
 
1166
        ComAssertComRCRet(rc, rc);
 
1167
    }
 
1168
 
 
1169
    int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId).ref(), aProgress);
 
1170
    if (RT_SUCCESS(r))
 
1171
    {
 
1172
        /* Drop configuration parameters for removed interface */
 
1173
        rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
 
1174
        rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
 
1175
        rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
 
1176
        rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
 
1177
 
 
1178
        return S_OK;
 
1179
    }
 
1180
 
 
1181
    return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
 
1182
#else
 
1183
    return E_NOTIMPL;
 
1184
#endif
 
1185
}
 
1186
 
 
1187
STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
 
1188
                                         IHostUSBDeviceFilter **aFilter)
 
1189
{
 
1190
#ifdef VBOX_WITH_USB
 
1191
    CheckComArgStrNotEmptyOrNull(aName);
 
1192
    CheckComArgOutPointerValid(aFilter);
 
1193
 
 
1194
    AutoCaller autoCaller(this);
 
1195
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
1196
 
 
1197
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
1198
 
 
1199
    ComObjPtr<HostUSBDeviceFilter> filter;
 
1200
    filter.createObject();
 
1201
    HRESULT rc = filter->init(this, aName);
 
1202
    ComAssertComRCRet(rc, rc);
 
1203
    rc = filter.queryInterfaceTo(aFilter);
 
1204
    AssertComRCReturn(rc, rc);
 
1205
    return S_OK;
 
1206
#else
 
1207
    /* Note: The GUI depends on this method returning E_NOTIMPL with no
 
1208
     * extended error info to indicate that USB is simply not available
 
1209
     * (w/o treating it as a failure), for example, as in OSE. */
 
1210
    NOREF(aName);
 
1211
    NOREF(aFilter);
 
1212
    ReturnComNotImplemented();
 
1213
#endif
 
1214
}
 
1215
 
 
1216
STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
 
1217
                                         IHostUSBDeviceFilter *aFilter)
 
1218
{
 
1219
#ifdef VBOX_WITH_USB
 
1220
    CheckComArgNotNull(aFilter);
 
1221
 
 
1222
    /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
 
1223
    AutoCaller autoCaller(this);
 
1224
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
1225
 
 
1226
    AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
 
1227
 
 
1228
    clearError();
 
1229
    MultiResult rc = checkUSBProxyService();
 
1230
    if (FAILED(rc)) return rc;
 
1231
 
 
1232
    ComObjPtr<HostUSBDeviceFilter> pFilter;
 
1233
    for (USBDeviceFilterList::iterator it = m->llChildren.begin();
 
1234
         it != m->llChildren.end();
 
1235
         ++it)
 
1236
    {
 
1237
        if (*it == aFilter)
 
1238
        {
 
1239
            pFilter = *it;
 
1240
            break;
 
1241
        }
 
1242
    }
 
1243
    if (pFilter.isNull())
 
1244
        return setError(VBOX_E_INVALID_OBJECT_STATE,
 
1245
                        tr("The given USB device filter is not created within this VirtualBox instance"));
 
1246
 
 
1247
    if (pFilter->mInList)
 
1248
        return setError(E_INVALIDARG,
 
1249
                        tr("The given USB device filter is already in the list"));
 
1250
 
 
1251
    /* iterate to the position... */
 
1252
    USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
 
1253
    std::advance(itPos, aPosition);
 
1254
    /* ...and insert */
 
1255
    m->llUSBDeviceFilters.insert(itPos, pFilter);
 
1256
    pFilter->mInList = true;
 
1257
 
 
1258
    /* notify the proxy (only when the filter is active) */
 
1259
    if (    m->pUSBProxyService->isActive()
 
1260
         && pFilter->getData().mActive)
 
1261
    {
 
1262
        ComAssertRet(pFilter->getId() == NULL, E_FAIL);
 
1263
        pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
 
1264
    }
 
1265
 
 
1266
    // save the global settings; for that we should hold only the VirtualBox lock
 
1267
    alock.release();
 
1268
    AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
 
1269
    return rc = m->pParent->saveSettings();
 
1270
#else
 
1271
    /* Note: The GUI depends on this method returning E_NOTIMPL with no
 
1272
     * extended error info to indicate that USB is simply not available
 
1273
     * (w/o treating it as a failure), for example, as in OSE. */
 
1274
    NOREF(aPosition);
 
1275
    NOREF(aFilter);
 
1276
    ReturnComNotImplemented();
 
1277
#endif
 
1278
}
 
1279
 
 
1280
STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
 
1281
{
 
1282
#ifdef VBOX_WITH_USB
 
1283
 
 
1284
    /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
 
1285
    AutoCaller autoCaller(this);
 
1286
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
1287
 
 
1288
    AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
 
1289
 
 
1290
    clearError();
 
1291
    MultiResult rc = checkUSBProxyService();
 
1292
    if (FAILED(rc)) return rc;
 
1293
 
 
1294
    if (!m->llUSBDeviceFilters.size())
 
1295
        return setError(E_INVALIDARG,
 
1296
                        tr("The USB device filter list is empty"));
 
1297
 
 
1298
    if (aPosition >= m->llUSBDeviceFilters.size())
 
1299
        return setError(E_INVALIDARG,
 
1300
                        tr("Invalid position: %lu (must be in range [0, %lu])"),
 
1301
                        aPosition, m->llUSBDeviceFilters.size() - 1);
 
1302
 
 
1303
    ComObjPtr<HostUSBDeviceFilter> filter;
 
1304
    {
 
1305
        /* iterate to the position... */
 
1306
        USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
 
1307
        std::advance (it, aPosition);
 
1308
        /* ...get an element from there... */
 
1309
        filter = *it;
 
1310
        /* ...and remove */
 
1311
        filter->mInList = false;
 
1312
        m->llUSBDeviceFilters.erase(it);
 
1313
    }
 
1314
 
 
1315
    /* notify the proxy (only when the filter is active) */
 
1316
    if (m->pUSBProxyService->isActive() && filter->getData().mActive)
 
1317
    {
 
1318
        ComAssertRet(filter->getId() != NULL, E_FAIL);
 
1319
        m->pUSBProxyService->removeFilter(filter->getId());
 
1320
        filter->getId() = NULL;
 
1321
    }
 
1322
 
 
1323
    // save the global settings; for that we should hold only the VirtualBox lock
 
1324
    alock.release();
 
1325
    AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
 
1326
    return rc = m->pParent->saveSettings();
 
1327
#else
 
1328
    /* Note: The GUI depends on this method returning E_NOTIMPL with no
 
1329
     * extended error info to indicate that USB is simply not available
 
1330
     * (w/o treating it as a failure), for example, as in OSE. */
 
1331
    NOREF(aPosition);
 
1332
    ReturnComNotImplemented();
 
1333
#endif
 
1334
}
 
1335
 
 
1336
STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
 
1337
{
 
1338
    CheckComArgStrNotEmptyOrNull(aName);
 
1339
    CheckComArgOutPointerValid(aDrive);
 
1340
 
 
1341
    ComObjPtr<Medium>medium;
 
1342
    HRESULT rc = findHostDriveByNameOrId(DeviceType_DVD, Utf8Str(aName), medium);
 
1343
    if (SUCCEEDED(rc))
 
1344
        return medium.queryInterfaceTo(aDrive);
 
1345
    else
 
1346
        return setError(rc, Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
 
1347
}
 
1348
 
 
1349
STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
 
1350
{
 
1351
    CheckComArgStrNotEmptyOrNull(aName);
 
1352
    CheckComArgOutPointerValid(aDrive);
 
1353
 
 
1354
    *aDrive = NULL;
 
1355
 
 
1356
    ComObjPtr<Medium>medium;
 
1357
    HRESULT rc = findHostDriveByNameOrId(DeviceType_Floppy, Utf8Str(aName), medium);
 
1358
    if (SUCCEEDED(rc))
 
1359
        return medium.queryInterfaceTo(aDrive);
 
1360
    else
 
1361
        return setError(rc, Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
 
1362
}
 
1363
 
 
1364
STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
 
1365
{
 
1366
#ifndef VBOX_WITH_HOSTNETIF_API
 
1367
    return E_NOTIMPL;
 
1368
#else
 
1369
    if (!name)
 
1370
        return E_INVALIDARG;
 
1371
    if (!networkInterface)
 
1372
        return E_POINTER;
 
1373
 
 
1374
    *networkInterface = NULL;
 
1375
    ComObjPtr<HostNetworkInterface> found;
 
1376
    std::list <ComObjPtr<HostNetworkInterface> > list;
 
1377
    int rc = NetIfList(list);
 
1378
    if (RT_FAILURE(rc))
 
1379
    {
 
1380
        Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
 
1381
        return E_FAIL;
 
1382
    }
 
1383
    std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
 
1384
    for (it = list.begin(); it != list.end(); ++it)
 
1385
    {
 
1386
        Bstr n;
 
1387
        (*it)->COMGETTER(Name) (n.asOutParam());
 
1388
        if (n == name)
 
1389
            found = *it;
 
1390
    }
 
1391
 
 
1392
    if (!found)
 
1393
        return setError(E_INVALIDARG,
 
1394
                        HostNetworkInterface::tr("The host network interface with the given name could not be found"));
 
1395
 
 
1396
    found->setVirtualBox(m->pParent);
 
1397
 
 
1398
    return found.queryInterfaceTo(networkInterface);
 
1399
#endif
 
1400
}
 
1401
 
 
1402
STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
 
1403
{
 
1404
#ifndef VBOX_WITH_HOSTNETIF_API
 
1405
    return E_NOTIMPL;
 
1406
#else
 
1407
    if (Guid(id).isEmpty())
 
1408
        return E_INVALIDARG;
 
1409
    if (!networkInterface)
 
1410
        return E_POINTER;
 
1411
 
 
1412
    *networkInterface = NULL;
 
1413
    ComObjPtr<HostNetworkInterface> found;
 
1414
    std::list <ComObjPtr<HostNetworkInterface> > list;
 
1415
    int rc = NetIfList(list);
 
1416
    if (RT_FAILURE(rc))
 
1417
    {
 
1418
        Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
 
1419
        return E_FAIL;
 
1420
    }
 
1421
    std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
 
1422
    for (it = list.begin(); it != list.end(); ++it)
 
1423
    {
 
1424
        Bstr g;
 
1425
        (*it)->COMGETTER(Id) (g.asOutParam());
 
1426
        if (g == id)
 
1427
            found = *it;
 
1428
    }
 
1429
 
 
1430
    if (!found)
 
1431
        return setError(E_INVALIDARG,
 
1432
                        HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
 
1433
 
 
1434
    found->setVirtualBox(m->pParent);
 
1435
 
 
1436
    return found.queryInterfaceTo(networkInterface);
 
1437
#endif
 
1438
}
 
1439
 
 
1440
STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
 
1441
                                                   ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
 
1442
{
 
1443
#ifdef VBOX_WITH_HOSTNETIF_API
 
1444
    std::list <ComObjPtr<HostNetworkInterface> > allList;
 
1445
    int rc = NetIfList(allList);
 
1446
    if (RT_FAILURE(rc))
 
1447
        return E_FAIL;
 
1448
 
 
1449
    std::list <ComObjPtr<HostNetworkInterface> > resultList;
 
1450
 
 
1451
    std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
 
1452
    for (it = allList.begin(); it != allList.end(); ++it)
 
1453
    {
 
1454
        HostNetworkInterfaceType_T t;
 
1455
        HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
 
1456
        if (FAILED(hr))
 
1457
            return hr;
 
1458
 
 
1459
        if (t == type)
 
1460
        {
 
1461
            (*it)->setVirtualBox(m->pParent);
 
1462
            resultList.push_back (*it);
 
1463
        }
 
1464
    }
 
1465
 
 
1466
    SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
 
1467
    filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
 
1468
 
 
1469
    return S_OK;
 
1470
#else
 
1471
    return E_NOTIMPL;
 
1472
#endif
 
1473
}
 
1474
 
 
1475
STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
 
1476
                                          IHostUSBDevice **aDevice)
 
1477
{
 
1478
#ifdef VBOX_WITH_USB
 
1479
    CheckComArgStrNotEmptyOrNull(aAddress);
 
1480
    CheckComArgOutPointerValid(aDevice);
 
1481
 
 
1482
    *aDevice = NULL;
 
1483
 
 
1484
    SafeIfaceArray<IHostUSBDevice> devsvec;
 
1485
    HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
 
1486
    if (FAILED(rc)) return rc;
 
1487
 
 
1488
    for (size_t i = 0; i < devsvec.size(); ++i)
 
1489
    {
 
1490
        Bstr address;
 
1491
        rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
 
1492
        if (FAILED(rc)) return rc;
 
1493
        if (address == aAddress)
 
1494
        {
 
1495
            return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
 
1496
        }
 
1497
    }
 
1498
 
 
1499
    return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
 
1500
                         tr("Could not find a USB device with address '%ls'"),
 
1501
                         aAddress);
 
1502
 
 
1503
#else   /* !VBOX_WITH_USB */
 
1504
    NOREF(aAddress);
 
1505
    NOREF(aDevice);
 
1506
    return E_NOTIMPL;
 
1507
#endif  /* !VBOX_WITH_USB */
 
1508
}
 
1509
 
 
1510
STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
 
1511
                                     IHostUSBDevice **aDevice)
 
1512
{
 
1513
#ifdef VBOX_WITH_USB
 
1514
    CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
 
1515
    CheckComArgOutPointerValid(aDevice);
 
1516
 
 
1517
    *aDevice = NULL;
 
1518
 
 
1519
    SafeIfaceArray<IHostUSBDevice> devsvec;
 
1520
    HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
 
1521
    if (FAILED(rc)) return rc;
 
1522
 
 
1523
    for (size_t i = 0; i < devsvec.size(); ++i)
 
1524
    {
 
1525
        Bstr id;
 
1526
        rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
 
1527
        if (FAILED(rc)) return rc;
 
1528
        if (id == aId)
 
1529
        {
 
1530
            return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
 
1531
        }
 
1532
    }
 
1533
 
 
1534
    return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
 
1535
        "Could not find a USB device with uuid {%RTuuid}"),
 
1536
        Guid (aId).raw());
 
1537
 
 
1538
#else   /* !VBOX_WITH_USB */
 
1539
    NOREF(aId);
 
1540
    NOREF(aDevice);
 
1541
    return E_NOTIMPL;
 
1542
#endif  /* !VBOX_WITH_USB */
 
1543
}
 
1544
 
 
1545
STDMETHODIMP Host::GenerateMACAddress(BSTR *aAddress)
 
1546
{
 
1547
    CheckComArgOutPointerValid(aAddress);
 
1548
    // no locking required
 
1549
    Utf8Str mac;
 
1550
    generateMACAddress(mac);
 
1551
    Bstr(mac).cloneTo(aAddress);
 
1552
    return S_OK;
 
1553
}
 
1554
 
 
1555
// public methods only for internal purposes
 
1556
////////////////////////////////////////////////////////////////////////////////
 
1557
 
 
1558
HRESULT Host::loadSettings(const settings::Host &data)
 
1559
{
 
1560
    HRESULT rc = S_OK;
 
1561
#ifdef VBOX_WITH_USB
 
1562
    AutoCaller autoCaller(this);
 
1563
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
1564
 
 
1565
    AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
 
1566
 
 
1567
    for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
 
1568
         it != data.llUSBDeviceFilters.end();
 
1569
         ++it)
 
1570
    {
 
1571
        const settings::USBDeviceFilter &f = *it;
 
1572
        ComObjPtr<HostUSBDeviceFilter> pFilter;
 
1573
        pFilter.createObject();
 
1574
        rc = pFilter->init(this, f);
 
1575
        if (FAILED(rc)) break;
 
1576
 
 
1577
        m->llUSBDeviceFilters.push_back(pFilter);
 
1578
        pFilter->mInList = true;
 
1579
 
 
1580
        /* notify the proxy (only when the filter is active) */
 
1581
        if (pFilter->getData().mActive)
 
1582
        {
 
1583
            HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
 
1584
            flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
 
1585
        }
 
1586
    }
 
1587
#else
 
1588
    NOREF(data);
 
1589
#endif /* VBOX_WITH_USB */
 
1590
    return rc;
 
1591
}
 
1592
 
 
1593
HRESULT Host::saveSettings(settings::Host &data)
 
1594
{
 
1595
#ifdef VBOX_WITH_USB
 
1596
    AutoCaller autoCaller(this);
 
1597
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
1598
 
 
1599
    AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS);
 
1600
    AutoReadLock alock2(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
 
1601
 
 
1602
    data.llUSBDeviceFilters.clear();
 
1603
 
 
1604
    for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
 
1605
         it != m->llUSBDeviceFilters.end();
 
1606
         ++it)
 
1607
    {
 
1608
        ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
 
1609
        settings::USBDeviceFilter f;
 
1610
        pFilter->saveSettings(f);
 
1611
        data.llUSBDeviceFilters.push_back(f);
 
1612
    }
 
1613
#else
 
1614
    NOREF(data);
 
1615
#endif /* VBOX_WITH_USB */
 
1616
 
 
1617
    return S_OK;
 
1618
}
 
1619
 
 
1620
/**
 
1621
 * Sets the given pointer to point to the static list of DVD or floppy
 
1622
 * drives in the Host instance data, depending on the @a mediumType
 
1623
 * parameter.
 
1624
 *
 
1625
 * This builds the list on the first call; it adds or removes host drives
 
1626
 * that may have changed if fRefresh == true.
 
1627
 *
 
1628
 * The caller must hold the m->drivesLock write lock before calling this.
 
1629
 * To protect the list to which the caller's pointer points, the caller
 
1630
 * must also hold that lock.
 
1631
 *
 
1632
 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
 
1633
 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
 
1634
 * @param pll Caller's pointer which gets set to the static list of host drives.
 
1635
 * @return
 
1636
 */
 
1637
HRESULT Host::getDrives(DeviceType_T mediumType,
 
1638
                        bool fRefresh,
 
1639
                        MediaList *&pll)
 
1640
{
 
1641
    HRESULT rc = S_OK;
 
1642
    Assert(m->drivesLock.isWriteLockOnCurrentThread());
 
1643
 
 
1644
    MediaList llNew;
 
1645
    MediaList *pllCached;
 
1646
    bool *pfListBuilt = NULL;
 
1647
 
 
1648
    switch (mediumType)
 
1649
    {
 
1650
        case DeviceType_DVD:
 
1651
            if (!m->fDVDDrivesListBuilt || fRefresh)
 
1652
            {
 
1653
                rc = buildDVDDrivesList(llNew);
 
1654
                if (FAILED(rc))
 
1655
                    return rc;
 
1656
                pfListBuilt = &m->fDVDDrivesListBuilt;
 
1657
            }
 
1658
            pllCached = &m->llDVDDrives;
 
1659
        break;
 
1660
 
 
1661
        case DeviceType_Floppy:
 
1662
            if (!m->fFloppyDrivesListBuilt || fRefresh)
 
1663
            {
 
1664
                rc = buildFloppyDrivesList(llNew);
 
1665
                if (FAILED(rc))
 
1666
                    return rc;
 
1667
                pfListBuilt = &m->fFloppyDrivesListBuilt;
 
1668
            }
 
1669
            pllCached = &m->llFloppyDrives;
 
1670
        break;
 
1671
 
 
1672
        default:
 
1673
            return E_INVALIDARG;
 
1674
    }
 
1675
 
 
1676
    if (pfListBuilt)
 
1677
    {
 
1678
        // a list was built in llNew above:
 
1679
        if (!*pfListBuilt)
 
1680
        {
 
1681
            // this was the first call (instance bool is still false): then just copy the whole list and return
 
1682
            *pllCached = llNew;
 
1683
            // and mark the instance data as "built"
 
1684
            *pfListBuilt = true;
 
1685
        }
 
1686
        else
 
1687
        {
 
1688
            // list was built, and this was a subsequent call: then compare the old and the new lists
 
1689
 
 
1690
            // remove drives from the cached list which are no longer present
 
1691
            for (MediaList::iterator itCached = pllCached->begin();
 
1692
                 itCached != pllCached->end();
 
1693
                 /*nothing */)
 
1694
            {
 
1695
                Medium *pCached = *itCached;
 
1696
                const Utf8Str strLocationCached = pCached->getLocationFull();
 
1697
                bool fFound = false;
 
1698
                for (MediaList::iterator itNew = llNew.begin();
 
1699
                     itNew != llNew.end();
 
1700
                     ++itNew)
 
1701
                {
 
1702
                    Medium *pNew = *itNew;
 
1703
                    const Utf8Str strLocationNew = pNew->getLocationFull();
 
1704
                    if (strLocationNew == strLocationCached)
 
1705
                    {
 
1706
                        fFound = true;
 
1707
                        break;
 
1708
                    }
 
1709
                }
 
1710
                if (!fFound)
 
1711
                    itCached = pllCached->erase(itCached);
 
1712
                else
 
1713
                    ++itCached;
 
1714
            }
 
1715
 
 
1716
            // add drives to the cached list that are not on there yet
 
1717
            for (MediaList::iterator itNew = llNew.begin();
 
1718
                 itNew != llNew.end();
 
1719
                 ++itNew)
 
1720
            {
 
1721
                Medium *pNew = *itNew;
 
1722
                const Utf8Str strLocationNew = pNew->getLocationFull();
 
1723
                bool fFound = false;
 
1724
                for (MediaList::iterator itCached = pllCached->begin();
 
1725
                     itCached != pllCached->end();
 
1726
                     ++itCached)
 
1727
                {
 
1728
                    Medium *pCached = *itCached;
 
1729
                    const Utf8Str strLocationCached = pCached->getLocationFull();
 
1730
                    if (strLocationNew == strLocationCached)
 
1731
                    {
 
1732
                        fFound = true;
 
1733
                        break;
 
1734
                    }
 
1735
                }
 
1736
 
 
1737
                if (!fFound)
 
1738
                    pllCached->push_back(pNew);
 
1739
            }
 
1740
        }
 
1741
    }
 
1742
 
 
1743
    // return cached list to caller
 
1744
    pll = pllCached;
 
1745
 
 
1746
    return rc;
 
1747
}
 
1748
 
 
1749
/**
 
1750
 * Goes through the list of host drives that would be returned by getDrives()
 
1751
 * and looks for a host drive with the given UUID. If found, it sets pMedium
 
1752
 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
 
1753
 *
 
1754
 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
 
1755
 * @param uuid Medium UUID of host drive to look for.
 
1756
 * @param fRefresh Whether to refresh the host drives list (see getDrives())
 
1757
 * @param pMedium Medium object, if found…
 
1758
 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
 
1759
 */
 
1760
HRESULT Host::findHostDriveById(DeviceType_T mediumType,
 
1761
                                const Guid &uuid,
 
1762
                                bool fRefresh,
 
1763
                                ComObjPtr<Medium> &pMedium)
 
1764
{
 
1765
    MediaList *pllMedia;
 
1766
 
 
1767
    AutoWriteLock wlock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
 
1768
    HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
 
1769
    if (SUCCEEDED(rc))
 
1770
    {
 
1771
        for (MediaList::iterator it = pllMedia->begin();
 
1772
             it != pllMedia->end();
 
1773
             ++it)
 
1774
        {
 
1775
            Medium *pThis = *it;
 
1776
            AutoCaller mediumCaller(pThis);
 
1777
            AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
 
1778
            if (pThis->getId() == uuid)
 
1779
            {
 
1780
                pMedium = pThis;
 
1781
                return S_OK;
 
1782
            }
 
1783
        }
 
1784
    }
 
1785
 
 
1786
    return VBOX_E_OBJECT_NOT_FOUND;
 
1787
}
 
1788
 
 
1789
/**
 
1790
 * Goes through the list of host drives that would be returned by getDrives()
 
1791
 * and looks for a host drive with the given name. If found, it sets pMedium
 
1792
 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
 
1793
 *
 
1794
 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
 
1795
 * @param strLocationFull Name (path) of host drive to look for.
 
1796
 * @param fRefresh Whether to refresh the host drives list (see getDrives())
 
1797
 * @param pMedium Medium object, if found…
 
1798
 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
 
1799
 */
 
1800
HRESULT Host::findHostDriveByName(DeviceType_T mediumType,
 
1801
                                  const Utf8Str &strLocationFull,
 
1802
                                  bool fRefresh,
 
1803
                                  ComObjPtr<Medium> &pMedium)
 
1804
{
 
1805
    MediaList *pllMedia;
 
1806
 
 
1807
    AutoWriteLock wlock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
 
1808
    HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
 
1809
    if (SUCCEEDED(rc))
 
1810
    {
 
1811
        for (MediaList::iterator it = pllMedia->begin();
 
1812
             it != pllMedia->end();
 
1813
             ++it)
 
1814
        {
 
1815
            Medium *pThis = *it;
 
1816
            AutoCaller mediumCaller(pThis);
 
1817
            AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
 
1818
            if (pThis->getLocationFull() == strLocationFull)
 
1819
            {
 
1820
                pMedium = pThis;
 
1821
                return S_OK;
 
1822
            }
 
1823
        }
 
1824
    }
 
1825
 
 
1826
    return VBOX_E_OBJECT_NOT_FOUND;
 
1827
}
 
1828
 
 
1829
/**
 
1830
 * Goes through the list of host drives that would be returned by getDrives()
 
1831
 * and looks for a host drive with the given name, location or ID. If found,
 
1832
 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
 
1833
 *
 
1834
 * @param mediumType  Must be DeviceType_DVD or DeviceType_Floppy.
 
1835
 * @param strNameOrId Name or full location or UUID of host drive to look for.
 
1836
 * @param pMedium     Medium object, if found…
 
1837
 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
 
1838
 */
 
1839
HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType,
 
1840
                                      const Utf8Str &strNameOrId,
 
1841
                                      ComObjPtr<Medium> &pMedium)
 
1842
{
 
1843
    AutoWriteLock wlock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
 
1844
 
 
1845
    Guid uuid(strNameOrId);
 
1846
    if (!uuid.isEmpty())
 
1847
        return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
 
1848
 
 
1849
    // string is not a syntactically valid UUID: try a name then
 
1850
    return findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
 
1851
}
 
1852
 
 
1853
/**
 
1854
 * Called from getDrives() to build the DVD drives list.
 
1855
 * @param pll
 
1856
 * @return
 
1857
 */
 
1858
HRESULT Host::buildDVDDrivesList(MediaList &list)
 
1859
{
 
1860
    HRESULT rc = S_OK;
 
1861
 
 
1862
    Assert(m->drivesLock.isWriteLockOnCurrentThread());
 
1863
 
 
1864
    try
 
1865
    {
 
1866
#if defined(RT_OS_WINDOWS)
 
1867
        int sz = GetLogicalDriveStrings(0, NULL);
 
1868
        TCHAR *hostDrives = new TCHAR[sz+1];
 
1869
        GetLogicalDriveStrings(sz, hostDrives);
 
1870
        wchar_t driveName[3] = { '?', ':', '\0' };
 
1871
        TCHAR *p = hostDrives;
 
1872
        do
 
1873
        {
 
1874
            if (GetDriveType(p) == DRIVE_CDROM)
 
1875
            {
 
1876
                driveName[0] = *p;
 
1877
                ComObjPtr<Medium> hostDVDDriveObj;
 
1878
                hostDVDDriveObj.createObject();
 
1879
                hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
 
1880
                list.push_back(hostDVDDriveObj);
 
1881
            }
 
1882
            p += _tcslen(p) + 1;
 
1883
        }
 
1884
        while (*p);
 
1885
        delete[] hostDrives;
 
1886
 
 
1887
#elif defined(RT_OS_SOLARIS)
 
1888
# ifdef VBOX_USE_LIBHAL
 
1889
        if (!getDVDInfoFromHal(list))
 
1890
# endif
 
1891
        {
 
1892
            getDVDInfoFromDevTree(list);
 
1893
        }
 
1894
 
 
1895
#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
 
1896
        if (RT_SUCCESS(m->hostDrives.updateDVDs()))
 
1897
            for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
 
1898
                SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
 
1899
            {
 
1900
                ComObjPtr<Medium> hostDVDDriveObj;
 
1901
                Utf8Str location(it->mDevice);
 
1902
                Utf8Str description(it->mDescription);
 
1903
                if (SUCCEEDED(rc))
 
1904
                    rc = hostDVDDriveObj.createObject();
 
1905
                if (SUCCEEDED(rc))
 
1906
                    rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
 
1907
                if (SUCCEEDED(rc))
 
1908
                    list.push_back(hostDVDDriveObj);
 
1909
            }
 
1910
#elif defined(RT_OS_DARWIN)
 
1911
        PDARWINDVD cur = DarwinGetDVDDrives();
 
1912
        while (cur)
 
1913
        {
 
1914
            ComObjPtr<Medium> hostDVDDriveObj;
 
1915
            hostDVDDriveObj.createObject();
 
1916
            hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
 
1917
            list.push_back(hostDVDDriveObj);
 
1918
 
 
1919
            /* next */
 
1920
            void *freeMe = cur;
 
1921
            cur = cur->pNext;
 
1922
            RTMemFree(freeMe);
 
1923
        }
 
1924
#else
 
1925
    /* PORTME */
 
1926
#endif
 
1927
    }
 
1928
    catch(std::bad_alloc &)
 
1929
    {
 
1930
        rc = E_OUTOFMEMORY;
 
1931
    }
 
1932
    return rc;
 
1933
}
 
1934
 
 
1935
/**
 
1936
 * Called from getDrives() to build the floppy drives list.
 
1937
 * @param list
 
1938
 * @return
 
1939
 */
 
1940
HRESULT Host::buildFloppyDrivesList(MediaList &list)
 
1941
{
 
1942
    HRESULT rc = S_OK;
 
1943
 
 
1944
    Assert(m->drivesLock.isWriteLockOnCurrentThread());
 
1945
 
 
1946
    try
 
1947
    {
 
1948
#ifdef RT_OS_WINDOWS
 
1949
        int sz = GetLogicalDriveStrings(0, NULL);
 
1950
        TCHAR *hostDrives = new TCHAR[sz+1];
 
1951
        GetLogicalDriveStrings(sz, hostDrives);
 
1952
        wchar_t driveName[3] = { '?', ':', '\0' };
 
1953
        TCHAR *p = hostDrives;
 
1954
        do
 
1955
        {
 
1956
            if (GetDriveType(p) == DRIVE_REMOVABLE)
 
1957
            {
 
1958
                driveName[0] = *p;
 
1959
                ComObjPtr<Medium> hostFloppyDriveObj;
 
1960
                hostFloppyDriveObj.createObject();
 
1961
                hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
 
1962
                list.push_back(hostFloppyDriveObj);
 
1963
            }
 
1964
            p += _tcslen(p) + 1;
 
1965
        }
 
1966
        while (*p);
 
1967
        delete[] hostDrives;
 
1968
#elif defined(RT_OS_LINUX)
 
1969
        if (RT_SUCCESS(m->hostDrives.updateFloppies()))
 
1970
            for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
 
1971
                SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
 
1972
            {
 
1973
                ComObjPtr<Medium> hostFloppyDriveObj;
 
1974
                Utf8Str location(it->mDevice);
 
1975
                Utf8Str description(it->mDescription);
 
1976
                if (SUCCEEDED(rc))
 
1977
                    rc = hostFloppyDriveObj.createObject();
 
1978
                if (SUCCEEDED(rc))
 
1979
                    rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
 
1980
                if (SUCCEEDED(rc))
 
1981
                    list.push_back(hostFloppyDriveObj);
 
1982
            }
 
1983
#else
 
1984
    NOREF(list);
 
1985
    /* PORTME */
 
1986
#endif
 
1987
    }
 
1988
    catch(std::bad_alloc &)
 
1989
    {
 
1990
        rc = E_OUTOFMEMORY;
 
1991
    }
 
1992
 
 
1993
    return rc;
 
1994
}
 
1995
 
 
1996
#ifdef VBOX_WITH_USB
 
1997
USBProxyService* Host::usbProxyService()
 
1998
{
 
1999
    return m->pUSBProxyService;
 
2000
}
 
2001
 
 
2002
HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
 
2003
{
 
2004
    AutoCaller autoCaller(this);
 
2005
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
2006
 
 
2007
    AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
 
2008
 
 
2009
    m->llChildren.push_back(pChild);
 
2010
 
 
2011
    return S_OK;
 
2012
}
 
2013
 
 
2014
HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
 
2015
{
 
2016
    AutoCaller autoCaller(this);
 
2017
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
2018
 
 
2019
    AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
 
2020
 
 
2021
    for (USBDeviceFilterList::iterator it = m->llChildren.begin();
 
2022
         it != m->llChildren.end();
 
2023
         ++it)
 
2024
    {
 
2025
        if (*it == pChild)
 
2026
        {
 
2027
            m->llChildren.erase(it);
 
2028
            break;
 
2029
        }
 
2030
    }
 
2031
 
 
2032
    return S_OK;
 
2033
}
 
2034
 
 
2035
VirtualBox* Host::parent()
 
2036
{
 
2037
    return m->pParent;
 
2038
}
 
2039
 
 
2040
/**
 
2041
 *  Called by setter methods of all USB device filters.
 
2042
 */
 
2043
HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
 
2044
                                      BOOL aActiveChanged /* = FALSE */)
 
2045
{
 
2046
    AutoCaller autoCaller(this);
 
2047
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
2048
 
 
2049
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
2050
 
 
2051
    if (aFilter->mInList)
 
2052
    {
 
2053
        if (aActiveChanged)
 
2054
        {
 
2055
            // insert/remove the filter from the proxy
 
2056
            if (aFilter->getData().mActive)
 
2057
            {
 
2058
                ComAssertRet(aFilter->getId() == NULL, E_FAIL);
 
2059
                aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
 
2060
            }
 
2061
            else
 
2062
            {
 
2063
                ComAssertRet(aFilter->getId() != NULL, E_FAIL);
 
2064
                m->pUSBProxyService->removeFilter(aFilter->getId());
 
2065
                aFilter->getId() = NULL;
 
2066
            }
 
2067
        }
 
2068
        else
 
2069
        {
 
2070
            if (aFilter->getData().mActive)
 
2071
            {
 
2072
                // update the filter in the proxy
 
2073
                ComAssertRet(aFilter->getId() != NULL, E_FAIL);
 
2074
                m->pUSBProxyService->removeFilter(aFilter->getId());
 
2075
                aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
 
2076
            }
 
2077
        }
 
2078
 
 
2079
        // save the global settings... yeah, on every single filter property change
 
2080
        // for that we should hold only the VirtualBox lock
 
2081
        alock.release();
 
2082
        AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
 
2083
        return m->pParent->saveSettings();
 
2084
    }
 
2085
 
 
2086
    return S_OK;
 
2087
}
 
2088
 
 
2089
 
 
2090
/**
 
2091
 * Interface for obtaining a copy of the USBDeviceFilterList,
 
2092
 * used by the USBProxyService.
 
2093
 *
 
2094
 * @param   aGlobalFilters      Where to put the global filter list copy.
 
2095
 * @param   aMachines           Where to put the machine vector.
 
2096
 */
 
2097
void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
 
2098
{
 
2099
    AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
 
2100
 
 
2101
    *aGlobalFilters = m->llUSBDeviceFilters;
 
2102
}
 
2103
 
 
2104
#endif /* VBOX_WITH_USB */
 
2105
 
 
2106
// private methods
 
2107
////////////////////////////////////////////////////////////////////////////////
 
2108
 
 
2109
#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
 
2110
 
 
2111
/**
 
2112
 * Helper function to get the slice number from a device path
 
2113
 *
 
2114
 * @param   pszDevLinkPath      Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
 
2115
 * @returns Pointer to the slice portion of the given path.
 
2116
 */
 
2117
static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
 
2118
{
 
2119
    char *pszFound = NULL;
 
2120
    char *pszSlice = strrchr(pszDevLinkPath, 's');
 
2121
    char *pszDisk  = strrchr(pszDevLinkPath, 'd');
 
2122
    if (pszSlice && pszSlice > pszDisk)
 
2123
        pszFound = pszSlice;
 
2124
    else
 
2125
        pszFound = pszDisk;
 
2126
 
 
2127
    if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
 
2128
        return pszFound;
 
2129
 
 
2130
    return NULL;
 
2131
}
 
2132
 
 
2133
/**
 
2134
 * Walk device links and returns an allocated path for the first one in the snapshot.
 
2135
 *
 
2136
 * @param   DevLink     Handle to the device link being walked.
 
2137
 * @param   pvArg       Opaque data containing the pointer to the path.
 
2138
 * @returns Pointer to an allocated device path string.
 
2139
 */
 
2140
static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
 
2141
{
 
2142
    char **ppszPath = (char **)pvArg;
 
2143
    *ppszPath = strdup(di_devlink_path(DevLink));
 
2144
    return DI_WALK_TERMINATE;
 
2145
}
 
2146
 
 
2147
/**
 
2148
 * Walk all devices in the system and enumerate CD/DVD drives.
 
2149
 * @param   Node        Handle to the current node.
 
2150
 * @param   pvArg       Opaque data (holds list pointer).
 
2151
 * @returns Solaris specific code whether to continue walking or not.
 
2152
 */
 
2153
static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
 
2154
{
 
2155
    PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
 
2156
 
 
2157
    /*
 
2158
     * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
 
2159
     * As unfortunately the Solaris drivers only export these common properties.
 
2160
     */
 
2161
    int *pInt = NULL;
 
2162
    if (   di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
 
2163
        || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
 
2164
    {
 
2165
        if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
 
2166
            && (   *pInt == DTYPE_RODIRECT                                              /* CDROM */
 
2167
                || *pInt == DTYPE_OPTICAL))                                             /* Optical Drive */
 
2168
        {
 
2169
            char *pszProduct = NULL;
 
2170
            if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
 
2171
            {
 
2172
                char *pszVendor = NULL;
 
2173
                if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
 
2174
                {
 
2175
                    /*
 
2176
                     * Found a DVD drive, we need to scan the minor nodes to find the correct
 
2177
                     * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
 
2178
                     */
 
2179
                    int Major = di_driver_major(Node);
 
2180
                    di_minor_t Minor = DI_MINOR_NIL;
 
2181
                    di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
 
2182
                    if (DevLink)
 
2183
                    {
 
2184
                        while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
 
2185
                        {
 
2186
                            dev_t Dev = di_minor_devt(Minor);
 
2187
                            if (   Major != (int)major(Dev)
 
2188
                                || di_minor_spectype(Minor) == S_IFBLK
 
2189
                                || di_minor_type(Minor) != DDM_MINOR)
 
2190
                            {
 
2191
                                continue;
 
2192
                            }
 
2193
 
 
2194
                            char *pszMinorPath = di_devfs_minor_path(Minor);
 
2195
                            if (!pszMinorPath)
 
2196
                                continue;
 
2197
 
 
2198
                            char *pszDevLinkPath = NULL;
 
2199
                            di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
 
2200
                            di_devfs_path_free(pszMinorPath);
 
2201
 
 
2202
                            if (pszDevLinkPath)
 
2203
                            {
 
2204
                                char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
 
2205
                                if (   pszSlice && !strcmp(pszSlice, "s2")
 
2206
                                    && !strncmp(pszDevLinkPath, "/dev/rdsk", sizeof("/dev/rdsk") - 1))   /* We want only raw disks */
 
2207
                                {
 
2208
                                    /*
 
2209
                                     * We've got a fully qualified DVD drive. Add it to the list.
 
2210
                                     */
 
2211
                                    PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
 
2212
                                    if (RT_LIKELY(pDrive))
 
2213
                                    {
 
2214
                                        RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
 
2215
                                        RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
 
2216
                                        if (*ppDrives)
 
2217
                                            pDrive->pNext = *ppDrives;
 
2218
                                        *ppDrives = pDrive;
 
2219
 
 
2220
                                        /* We're not interested in any of the other slices, stop minor nodes traversal. */
 
2221
                                        free(pszDevLinkPath);
 
2222
                                        break;
 
2223
                                    }
 
2224
                                }
 
2225
                                free(pszDevLinkPath);
 
2226
                            }
 
2227
                        }
 
2228
                        di_devlink_fini(&DevLink);
 
2229
                    }
 
2230
                }
 
2231
            }
 
2232
        }
 
2233
    }
 
2234
    return DI_WALK_CONTINUE;
 
2235
}
 
2236
 
 
2237
/**
 
2238
 * Solaris specific function to enumerate CD/DVD drives via the device tree.
 
2239
 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
 
2240
 */
 
2241
void Host::getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
 
2242
{
 
2243
    PSOLARISDVD pDrives = NULL;
 
2244
    di_node_t RootNode = di_init("/", DINFOCPYALL);
 
2245
    if (RootNode != DI_NODE_NIL)
 
2246
        di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
 
2247
 
 
2248
    di_fini(RootNode);
 
2249
 
 
2250
    while (pDrives)
 
2251
    {
 
2252
        ComObjPtr<Medium> hostDVDDriveObj;
 
2253
        hostDVDDriveObj.createObject();
 
2254
        hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
 
2255
        list.push_back(hostDVDDriveObj);
 
2256
 
 
2257
        void *pvDrive = pDrives;
 
2258
        pDrives = pDrives->pNext;
 
2259
        RTMemFree(pvDrive);
 
2260
    }
 
2261
}
 
2262
 
 
2263
/* Solaris hosts, loading libhal at runtime */
 
2264
 
 
2265
/**
 
2266
 * Helper function to query the hal subsystem for information about DVD drives attached to the
 
2267
 * system.
 
2268
 *
 
2269
 * @returns true if information was successfully obtained, false otherwise
 
2270
 * @retval  list drives found will be attached to this list
 
2271
 */
 
2272
bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
 
2273
{
 
2274
    bool halSuccess = false;
 
2275
    DBusError dbusError;
 
2276
    if (!gLibHalCheckPresence())
 
2277
        return false;
 
2278
    gDBusErrorInit (&dbusError);
 
2279
    DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
 
2280
    if (dbusConnection != 0)
 
2281
    {
 
2282
        LibHalContext *halContext = gLibHalCtxNew();
 
2283
        if (halContext != 0)
 
2284
        {
 
2285
            if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
 
2286
            {
 
2287
                if (gLibHalCtxInit(halContext, &dbusError))
 
2288
                {
 
2289
                    int numDevices;
 
2290
                    char **halDevices = gLibHalFindDeviceStringMatch(halContext,
 
2291
                                                "storage.drive_type", "cdrom",
 
2292
                                                &numDevices, &dbusError);
 
2293
                    if (halDevices != 0)
 
2294
                    {
 
2295
                        /* Hal is installed and working, so if no devices are reported, assume
 
2296
                           that there are none. */
 
2297
                        halSuccess = true;
 
2298
                        for (int i = 0; i < numDevices; i++)
 
2299
                        {
 
2300
                            char *devNode = gLibHalDeviceGetPropertyString(halContext,
 
2301
                                                    halDevices[i], "block.device", &dbusError);
 
2302
#ifdef RT_OS_SOLARIS
 
2303
                            /* The CD/DVD ioctls work only for raw device nodes. */
 
2304
                            char *tmp = getfullrawname(devNode);
 
2305
                            gLibHalFreeString(devNode);
 
2306
                            devNode = tmp;
 
2307
#endif
 
2308
 
 
2309
                            if (devNode != 0)
 
2310
                            {
 
2311
//                                if (validateDevice(devNode, true))
 
2312
//                                {
 
2313
                                    Utf8Str description;
 
2314
                                    char *vendor, *product;
 
2315
                                    /* We do not check the error here, as this field may
 
2316
                                       not even exist. */
 
2317
                                    vendor = gLibHalDeviceGetPropertyString(halContext,
 
2318
                                                    halDevices[i], "info.vendor", 0);
 
2319
                                    product = gLibHalDeviceGetPropertyString(halContext,
 
2320
                                                    halDevices[i], "info.product", &dbusError);
 
2321
                                    if ((product != 0 && product[0] != 0))
 
2322
                                    {
 
2323
                                        if ((vendor != 0) && (vendor[0] != 0))
 
2324
                                        {
 
2325
                                            description = Utf8StrFmt ("%s %s",
 
2326
                                                                      vendor, product);
 
2327
                                        }
 
2328
                                        else
 
2329
                                        {
 
2330
                                            description = product;
 
2331
                                        }
 
2332
                                        ComObjPtr<Medium> hostDVDDriveObj;
 
2333
                                        hostDVDDriveObj.createObject();
 
2334
                                        hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
 
2335
                                                              Bstr(devNode), Bstr(description));
 
2336
                                        list.push_back (hostDVDDriveObj);
 
2337
                                    }
 
2338
                                    else
 
2339
                                    {
 
2340
                                        if (product == 0)
 
2341
                                        {
 
2342
                                            LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s.  dbus error: %s (%s)\n",
 
2343
                                                    halDevices[i], dbusError.name, dbusError.message));
 
2344
                                            gDBusErrorFree(&dbusError);
 
2345
                                        }
 
2346
                                        ComObjPtr<Medium> hostDVDDriveObj;
 
2347
                                        hostDVDDriveObj.createObject();
 
2348
                                        hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
 
2349
                                                              Bstr(devNode));
 
2350
                                        list.push_back (hostDVDDriveObj);
 
2351
                                    }
 
2352
                                    if (vendor != 0)
 
2353
                                    {
 
2354
                                        gLibHalFreeString(vendor);
 
2355
                                    }
 
2356
                                    if (product != 0)
 
2357
                                    {
 
2358
                                        gLibHalFreeString(product);
 
2359
                                    }
 
2360
//                                }
 
2361
//                                else
 
2362
//                                {
 
2363
//                                    LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
 
2364
//                                }
 
2365
#ifndef RT_OS_SOLARIS
 
2366
                                gLibHalFreeString(devNode);
 
2367
#else
 
2368
                                free(devNode);
 
2369
#endif
 
2370
                            }
 
2371
                            else
 
2372
                            {
 
2373
                                LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s.  dbus error: %s (%s)\n",
 
2374
                                        halDevices[i], dbusError.name, dbusError.message));
 
2375
                                gDBusErrorFree(&dbusError);
 
2376
                            }
 
2377
                        }
 
2378
                        gLibHalFreeStringArray(halDevices);
 
2379
                    }
 
2380
                    else
 
2381
                    {
 
2382
                        LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\".  dbus error: %s (%s)\n", dbusError.name, dbusError.message));
 
2383
                        gDBusErrorFree(&dbusError);
 
2384
                    }
 
2385
                    if (!gLibHalCtxShutdown(halContext, &dbusError))  /* what now? */
 
2386
                    {
 
2387
                        LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context.  dbus error: %s (%s)\n", dbusError.name, dbusError.message));
 
2388
                        gDBusErrorFree(&dbusError);
 
2389
                    }
 
2390
                }
 
2391
                else
 
2392
                {
 
2393
                    LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context.  dbus error: %s (%s)\n", dbusError.name, dbusError.message));
 
2394
                    gDBusErrorFree(&dbusError);
 
2395
                }
 
2396
                gLibHalCtxFree(halContext);
 
2397
            }
 
2398
            else
 
2399
            {
 
2400
                LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
 
2401
            }
 
2402
        }
 
2403
        else
 
2404
        {
 
2405
            LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
 
2406
        }
 
2407
        gDBusConnectionUnref(dbusConnection);
 
2408
    }
 
2409
    else
 
2410
    {
 
2411
        LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus.  dbus error: %s (%s)\n", dbusError.name, dbusError.message));
 
2412
        gDBusErrorFree(&dbusError);
 
2413
    }
 
2414
    return halSuccess;
 
2415
}
 
2416
 
 
2417
 
 
2418
/**
 
2419
 * Helper function to query the hal subsystem for information about floppy drives attached to the
 
2420
 * system.
 
2421
 *
 
2422
 * @returns true if information was successfully obtained, false otherwise
 
2423
 * @retval  list drives found will be attached to this list
 
2424
 */
 
2425
bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
 
2426
{
 
2427
    bool halSuccess = false;
 
2428
    DBusError dbusError;
 
2429
    if (!gLibHalCheckPresence())
 
2430
        return false;
 
2431
    gDBusErrorInit (&dbusError);
 
2432
    DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
 
2433
    if (dbusConnection != 0)
 
2434
    {
 
2435
        LibHalContext *halContext = gLibHalCtxNew();
 
2436
        if (halContext != 0)
 
2437
        {
 
2438
            if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
 
2439
            {
 
2440
                if (gLibHalCtxInit(halContext, &dbusError))
 
2441
                {
 
2442
                    int numDevices;
 
2443
                    char **halDevices = gLibHalFindDeviceStringMatch(halContext,
 
2444
                                                "storage.drive_type", "floppy",
 
2445
                                                &numDevices, &dbusError);
 
2446
                    if (halDevices != 0)
 
2447
                    {
 
2448
                        /* Hal is installed and working, so if no devices are reported, assume
 
2449
                           that there are none. */
 
2450
                        halSuccess = true;
 
2451
                        for (int i = 0; i < numDevices; i++)
 
2452
                        {
 
2453
                            char *driveType = gLibHalDeviceGetPropertyString(halContext,
 
2454
                                                    halDevices[i], "storage.drive_type", 0);
 
2455
                            if (driveType != 0)
 
2456
                            {
 
2457
                                if (strcmp(driveType, "floppy") != 0)
 
2458
                                {
 
2459
                                    gLibHalFreeString(driveType);
 
2460
                                    continue;
 
2461
                                }
 
2462
                                gLibHalFreeString(driveType);
 
2463
                            }
 
2464
                            else
 
2465
                            {
 
2466
                                /* An error occurred.  The attribute "storage.drive_type"
 
2467
                                   probably didn't exist. */
 
2468
                                continue;
 
2469
                            }
 
2470
                            char *devNode = gLibHalDeviceGetPropertyString(halContext,
 
2471
                                                    halDevices[i], "block.device", &dbusError);
 
2472
                            if (devNode != 0)
 
2473
                            {
 
2474
//                                if (validateDevice(devNode, false))
 
2475
//                                {
 
2476
                                    Utf8Str description;
 
2477
                                    char *vendor, *product;
 
2478
                                    /* We do not check the error here, as this field may
 
2479
                                       not even exist. */
 
2480
                                    vendor = gLibHalDeviceGetPropertyString(halContext,
 
2481
                                                    halDevices[i], "info.vendor", 0);
 
2482
                                    product = gLibHalDeviceGetPropertyString(halContext,
 
2483
                                                    halDevices[i], "info.product", &dbusError);
 
2484
                                    if ((product != 0) && (product[0] != 0))
 
2485
                                    {
 
2486
                                        if ((vendor != 0) && (vendor[0] != 0))
 
2487
                                        {
 
2488
                                            description = Utf8StrFmt ("%s %s",
 
2489
                                                                      vendor, product);
 
2490
                                        }
 
2491
                                        else
 
2492
                                        {
 
2493
                                            description = product;
 
2494
                                        }
 
2495
                                        ComObjPtr<Medium> hostFloppyDrive;
 
2496
                                        hostFloppyDrive.createObject();
 
2497
                                        hostFloppyDrive->init(m->pParent, DeviceType_DVD,
 
2498
                                                              Bstr(devNode), Bstr(description));
 
2499
                                        list.push_back (hostFloppyDrive);
 
2500
                                    }
 
2501
                                    else
 
2502
                                    {
 
2503
                                        if (product == 0)
 
2504
                                        {
 
2505
                                            LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s.  dbus error: %s (%s)\n",
 
2506
                                                    halDevices[i], dbusError.name, dbusError.message));
 
2507
                                            gDBusErrorFree(&dbusError);
 
2508
                                        }
 
2509
                                        ComObjPtr<Medium> hostFloppyDrive;
 
2510
                                        hostFloppyDrive.createObject();
 
2511
                                        hostFloppyDrive->init(m->pParent, DeviceType_DVD,
 
2512
                                                              Bstr(devNode));
 
2513
                                        list.push_back (hostFloppyDrive);
 
2514
                                    }
 
2515
                                    if (vendor != 0)
 
2516
                                    {
 
2517
                                        gLibHalFreeString(vendor);
 
2518
                                    }
 
2519
                                    if (product != 0)
 
2520
                                    {
 
2521
                                        gLibHalFreeString(product);
 
2522
                                    }
 
2523
//                                }
 
2524
//                                else
 
2525
//                                {
 
2526
//                                    LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
 
2527
//                                }
 
2528
                                gLibHalFreeString(devNode);
 
2529
                            }
 
2530
                            else
 
2531
                            {
 
2532
                                LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s.  dbus error: %s (%s)\n",
 
2533
                                        halDevices[i], dbusError.name, dbusError.message));
 
2534
                                gDBusErrorFree(&dbusError);
 
2535
                            }
 
2536
                        }
 
2537
                        gLibHalFreeStringArray(halDevices);
 
2538
                    }
 
2539
                    else
 
2540
                    {
 
2541
                        LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\".  dbus error: %s (%s)\n", dbusError.name, dbusError.message));
 
2542
                        gDBusErrorFree(&dbusError);
 
2543
                    }
 
2544
                    if (!gLibHalCtxShutdown(halContext, &dbusError))  /* what now? */
 
2545
                    {
 
2546
                        LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context.  dbus error: %s (%s)\n", dbusError.name, dbusError.message));
 
2547
                        gDBusErrorFree(&dbusError);
 
2548
                    }
 
2549
                }
 
2550
                else
 
2551
                {
 
2552
                    LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context.  dbus error: %s (%s)\n", dbusError.name, dbusError.message));
 
2553
                    gDBusErrorFree(&dbusError);
 
2554
                }
 
2555
                gLibHalCtxFree(halContext);
 
2556
            }
 
2557
            else
 
2558
            {
 
2559
                LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
 
2560
            }
 
2561
        }
 
2562
        else
 
2563
        {
 
2564
            LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
 
2565
        }
 
2566
        gDBusConnectionUnref(dbusConnection);
 
2567
    }
 
2568
    else
 
2569
    {
 
2570
        LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus.  dbus error: %s (%s)\n", dbusError.name, dbusError.message));
 
2571
        gDBusErrorFree(&dbusError);
 
2572
    }
 
2573
    return halSuccess;
 
2574
}
 
2575
#endif  /* RT_OS_SOLARIS and VBOX_USE_HAL */
 
2576
 
 
2577
/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
 
2578
#if defined(RT_OS_SOLARIS)
 
2579
 
 
2580
/**
 
2581
 * Helper function to parse the given mount file and add found entries
 
2582
 */
 
2583
void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
 
2584
{
 
2585
#ifdef RT_OS_LINUX
 
2586
    FILE *mtab = setmntent(mountTable, "r");
 
2587
    if (mtab)
 
2588
    {
 
2589
        struct mntent *mntent;
 
2590
        char *mnt_type;
 
2591
        char *mnt_dev;
 
2592
        char *tmp;
 
2593
        while ((mntent = getmntent(mtab)))
 
2594
        {
 
2595
            mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
 
2596
            mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
 
2597
            strcpy(mnt_type, mntent->mnt_type);
 
2598
            strcpy(mnt_dev, mntent->mnt_fsname);
 
2599
            // supermount fs case
 
2600
            if (strcmp(mnt_type, "supermount") == 0)
 
2601
            {
 
2602
                tmp = strstr(mntent->mnt_opts, "fs=");
 
2603
                if (tmp)
 
2604
                {
 
2605
                    free(mnt_type);
 
2606
                    mnt_type = strdup(tmp + strlen("fs="));
 
2607
                    if (mnt_type)
 
2608
                    {
 
2609
                        tmp = strchr(mnt_type, ',');
 
2610
                        if (tmp)
 
2611
                            *tmp = '\0';
 
2612
                    }
 
2613
                }
 
2614
                tmp = strstr(mntent->mnt_opts, "dev=");
 
2615
                if (tmp)
 
2616
                {
 
2617
                    free(mnt_dev);
 
2618
                    mnt_dev = strdup(tmp + strlen("dev="));
 
2619
                    if (mnt_dev)
 
2620
                    {
 
2621
                        tmp = strchr(mnt_dev, ',');
 
2622
                        if (tmp)
 
2623
                            *tmp = '\0';
 
2624
                    }
 
2625
                }
 
2626
            }
 
2627
            // use strstr here to cover things fs types like "udf,iso9660"
 
2628
            if (strstr(mnt_type, "iso9660") == 0)
 
2629
            {
 
2630
                /** @todo check whether we've already got the drive in our list! */
 
2631
                if (validateDevice(mnt_dev, true))
 
2632
                {
 
2633
                    ComObjPtr<Medium> hostDVDDriveObj;
 
2634
                    hostDVDDriveObj.createObject();
 
2635
                    hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
 
2636
                    list.push_back (hostDVDDriveObj);
 
2637
                }
 
2638
            }
 
2639
            free(mnt_dev);
 
2640
            free(mnt_type);
 
2641
        }
 
2642
        endmntent(mtab);
 
2643
    }
 
2644
#else  // RT_OS_SOLARIS
 
2645
    FILE *mntFile = fopen(mountTable, "r");
 
2646
    if (mntFile)
 
2647
    {
 
2648
        struct mnttab mntTab;
 
2649
        while (getmntent(mntFile, &mntTab) == 0)
 
2650
        {
 
2651
            const char *mountName = mntTab.mnt_special;
 
2652
            const char *mountPoint = mntTab.mnt_mountp;
 
2653
            const char *mountFSType = mntTab.mnt_fstype;
 
2654
            if (mountName && mountPoint && mountFSType)
 
2655
            {
 
2656
                // skip devices we are not interested in
 
2657
                if ((*mountName && mountName[0] == '/') &&                      // skip 'fake' devices (like -hosts, proc, fd, swap)
 
2658
                    (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 &&  // skip devfs (i.e. /devices)
 
2659
                                      strncmp(mountFSType, "dev", 3) != 0 &&    // skip dev (i.e. /dev)
 
2660
                                      strncmp(mountFSType, "lofs", 4) != 0)))   // skip loop-back file-system (lofs)
 
2661
                {
 
2662
                    char *rawDevName = getfullrawname((char *)mountName);
 
2663
                    if (validateDevice(rawDevName, true))
 
2664
                    {
 
2665
                        ComObjPtr<Medium> hostDVDDriveObj;
 
2666
                        hostDVDDriveObj.createObject();
 
2667
                        hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
 
2668
                        list.push_back (hostDVDDriveObj);
 
2669
                    }
 
2670
                    free(rawDevName);
 
2671
                }
 
2672
            }
 
2673
        }
 
2674
 
 
2675
        fclose(mntFile);
 
2676
    }
 
2677
#endif
 
2678
}
 
2679
 
 
2680
/**
 
2681
 * Helper function to check whether the given device node is a valid drive
 
2682
 */
 
2683
bool Host::validateDevice(const char *deviceNode, bool isCDROM)
 
2684
{
 
2685
    struct stat statInfo;
 
2686
    bool retValue = false;
 
2687
 
 
2688
    // sanity check
 
2689
    if (!deviceNode)
 
2690
    {
 
2691
        return false;
 
2692
    }
 
2693
 
 
2694
    // first a simple stat() call
 
2695
    if (stat(deviceNode, &statInfo) < 0)
 
2696
    {
 
2697
        return false;
 
2698
    }
 
2699
    else
 
2700
    {
 
2701
        if (isCDROM)
 
2702
        {
 
2703
            if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
 
2704
            {
 
2705
                int fileHandle;
 
2706
                // now try to open the device
 
2707
                fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
 
2708
                if (fileHandle >= 0)
 
2709
                {
 
2710
                    cdrom_subchnl cdChannelInfo;
 
2711
                    cdChannelInfo.cdsc_format = CDROM_MSF;
 
2712
                    // this call will finally reveal the whole truth
 
2713
#ifdef RT_OS_LINUX
 
2714
                    if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
 
2715
                        (errno == EIO) || (errno == ENOENT) ||
 
2716
                        (errno == EINVAL) || (errno == ENOMEDIUM))
 
2717
#else
 
2718
                    if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
 
2719
                        (errno == EIO) || (errno == ENOENT) ||
 
2720
                        (errno == EINVAL))
 
2721
#endif
 
2722
                    {
 
2723
                        retValue = true;
 
2724
                    }
 
2725
                    close(fileHandle);
 
2726
                }
 
2727
            }
 
2728
        } else
 
2729
        {
 
2730
            // floppy case
 
2731
            if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
 
2732
            {
 
2733
                /// @todo do some more testing, maybe a nice IOCTL!
 
2734
                retValue = true;
 
2735
            }
 
2736
        }
 
2737
    }
 
2738
    return retValue;
 
2739
}
 
2740
#endif // RT_OS_SOLARIS
 
2741
 
 
2742
#ifdef VBOX_WITH_USB
 
2743
/**
 
2744
 *  Checks for the presence and status of the USB Proxy Service.
 
2745
 *  Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
 
2746
 *  warning) if the proxy service is not available due to the way the host is
 
2747
 *  configured (at present, that means that usbfs and hal/DBus are not
 
2748
 *  available on a Linux host) or E_FAIL and a corresponding error message
 
2749
 *  otherwise. Intended to be used by methods that rely on the Proxy Service
 
2750
 *  availability.
 
2751
 *
 
2752
 *  @note This method may return a warning result code. It is recommended to use
 
2753
 *        MultiError to store the return value.
 
2754
 *
 
2755
 *  @note Locks this object for reading.
 
2756
 */
 
2757
HRESULT Host::checkUSBProxyService()
 
2758
{
 
2759
    AutoCaller autoCaller(this);
 
2760
    if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
2761
 
 
2762
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
2763
 
 
2764
    AssertReturn(m->pUSBProxyService, E_FAIL);
 
2765
    if (!m->pUSBProxyService->isActive())
 
2766
    {
 
2767
        /* disable the USB controller completely to avoid assertions if the
 
2768
         * USB proxy service could not start. */
 
2769
 
 
2770
        switch (m->pUSBProxyService->getLastError())
 
2771
        {
 
2772
            case VERR_FILE_NOT_FOUND:  /** @todo what does this mean? */
 
2773
                return setWarning(E_FAIL,
 
2774
                                  tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
 
2775
            case VERR_VUSB_USB_DEVICE_PERMISSION:
 
2776
                return setWarning(E_FAIL,
 
2777
                                  tr("VirtualBox is not currently allowed to access USB devices.  You can change this by adding your user to the 'vboxusers' group.  Please see the user manual for a more detailed explanation"));
 
2778
            case VERR_VUSB_USBFS_PERMISSION:
 
2779
                return setWarning(E_FAIL,
 
2780
                                  tr("VirtualBox is not currently allowed to access USB devices.  You can change this by allowing your user to access the 'usbfs' folder and files.  Please see the user manual for a more detailed explanation"));
 
2781
            case VINF_SUCCESS:
 
2782
                return setWarning(E_FAIL,
 
2783
                                  tr("The USB Proxy Service has not yet been ported to this host"));
 
2784
            default:
 
2785
                return setWarning (E_FAIL, "%s: %Rrc",
 
2786
                                   tr ("Could not load the Host USB Proxy service"),
 
2787
                                   m->pUSBProxyService->getLastError());
 
2788
        }
 
2789
    }
 
2790
 
 
2791
    return S_OK;
 
2792
}
 
2793
#endif /* VBOX_WITH_USB */
 
2794
 
 
2795
#ifdef VBOX_WITH_RESOURCE_USAGE_API
 
2796
 
 
2797
void Host::registerMetrics(PerformanceCollector *aCollector)
 
2798
{
 
2799
    pm::CollectorHAL *hal = aCollector->getHAL();
 
2800
    /* Create sub metrics */
 
2801
    pm::SubMetric *cpuLoadUser   = new pm::SubMetric("CPU/Load/User",
 
2802
        "Percentage of processor time spent in user mode.");
 
2803
    pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
 
2804
        "Percentage of processor time spent in kernel mode.");
 
2805
    pm::SubMetric *cpuLoadIdle   = new pm::SubMetric("CPU/Load/Idle",
 
2806
        "Percentage of processor time spent idling.");
 
2807
    pm::SubMetric *cpuMhzSM      = new pm::SubMetric("CPU/MHz",
 
2808
        "Average of current frequency of all processors.");
 
2809
    pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
 
2810
        "Total physical memory installed.");
 
2811
    pm::SubMetric *ramUsageUsed  = new pm::SubMetric("RAM/Usage/Used",
 
2812
        "Physical memory currently occupied.");
 
2813
    pm::SubMetric *ramUsageFree  = new pm::SubMetric("RAM/Usage/Free",
 
2814
        "Physical memory currently available to applications.");
 
2815
    pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
 
2816
        "Total physical memory used by the hypervisor.");
 
2817
    pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
 
2818
        "Total physical memory free inside the hypervisor.");
 
2819
    pm::SubMetric *ramVMMBallooned  = new pm::SubMetric("RAM/VMM/Ballooned",
 
2820
        "Total physical memory ballooned by the hypervisor.");
 
2821
    pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
 
2822
        "Total physical memory shared between VMs.");
 
2823
 
 
2824
 
 
2825
    /* Create and register base metrics */
 
2826
    IUnknown *objptr;
 
2827
    ComObjPtr<Host> tmp = this;
 
2828
    tmp.queryInterfaceTo(&objptr);
 
2829
    pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
 
2830
                                          cpuLoadIdle);
 
2831
    aCollector->registerBaseMetric (cpuLoad);
 
2832
    pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
 
2833
    aCollector->registerBaseMetric (cpuMhz);
 
2834
    pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr,
 
2835
                                                    ramUsageTotal,
 
2836
                                                    ramUsageUsed,
 
2837
                                                    ramUsageFree);
 
2838
    aCollector->registerBaseMetric (ramUsage);
 
2839
    pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), objptr,
 
2840
                                                ramVMMUsed,
 
2841
                                                ramVMMFree,
 
2842
                                                ramVMMBallooned,
 
2843
                                                ramVMMShared);
 
2844
    aCollector->registerBaseMetric (ramVmm);
 
2845
 
 
2846
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
 
2847
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
 
2848
                                              new pm::AggregateAvg()));
 
2849
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
 
2850
                                              new pm::AggregateMin()));
 
2851
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
 
2852
                                              new pm::AggregateMax()));
 
2853
 
 
2854
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
 
2855
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
 
2856
                                              new pm::AggregateAvg()));
 
2857
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
 
2858
                                              new pm::AggregateMin()));
 
2859
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
 
2860
                                              new pm::AggregateMax()));
 
2861
 
 
2862
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
 
2863
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
 
2864
                                              new pm::AggregateAvg()));
 
2865
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
 
2866
                                              new pm::AggregateMin()));
 
2867
    aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
 
2868
                                              new pm::AggregateMax()));
 
2869
 
 
2870
    aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
 
2871
    aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
 
2872
                                              new pm::AggregateAvg()));
 
2873
    aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
 
2874
                                              new pm::AggregateMin()));
 
2875
    aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
 
2876
                                              new pm::AggregateMax()));
 
2877
 
 
2878
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
 
2879
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
 
2880
                                              new pm::AggregateAvg()));
 
2881
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
 
2882
                                              new pm::AggregateMin()));
 
2883
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
 
2884
                                              new pm::AggregateMax()));
 
2885
 
 
2886
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
 
2887
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
 
2888
                                              new pm::AggregateAvg()));
 
2889
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
 
2890
                                              new pm::AggregateMin()));
 
2891
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
 
2892
                                              new pm::AggregateMax()));
 
2893
 
 
2894
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
 
2895
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
 
2896
                                              new pm::AggregateAvg()));
 
2897
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
 
2898
                                              new pm::AggregateMin()));
 
2899
    aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
 
2900
                                              new pm::AggregateMax()));
 
2901
 
 
2902
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
 
2903
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
 
2904
                                              new pm::AggregateAvg()));
 
2905
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
 
2906
                                              new pm::AggregateMin()));
 
2907
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
 
2908
                                              new pm::AggregateMax()));
 
2909
 
 
2910
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
 
2911
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
 
2912
                                              new pm::AggregateAvg()));
 
2913
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
 
2914
                                              new pm::AggregateMin()));
 
2915
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
 
2916
                                              new pm::AggregateMax()));
 
2917
 
 
2918
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
 
2919
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
 
2920
                                              new pm::AggregateAvg()));
 
2921
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
 
2922
                                              new pm::AggregateMin()));
 
2923
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
 
2924
                                              new pm::AggregateMax()));
 
2925
 
 
2926
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
 
2927
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
 
2928
                                              new pm::AggregateAvg()));
 
2929
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
 
2930
                                              new pm::AggregateMin()));
 
2931
    aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
 
2932
                                              new pm::AggregateMax()));
 
2933
}
 
2934
 
 
2935
void Host::unregisterMetrics (PerformanceCollector *aCollector)
 
2936
{
 
2937
    aCollector->unregisterMetricsFor(this);
 
2938
    aCollector->unregisterBaseMetricsFor(this);
 
2939
}
 
2940
 
 
2941
 
 
2942
/* static */
 
2943
void Host::generateMACAddress(Utf8Str &mac)
 
2944
{
 
2945
    /*
 
2946
     * Our strategy is as follows: the first three bytes are our fixed
 
2947
     * vendor ID (080027). The remaining 3 bytes will be taken from the
 
2948
     * start of a GUID. This is a fairly safe algorithm.
 
2949
     */
 
2950
    Guid guid;
 
2951
    guid.create();
 
2952
    mac = Utf8StrFmt("080027%02X%02X%02X",
 
2953
                     guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
 
2954
}
 
2955
 
 
2956
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
 
2957
 
 
2958
/* vi: set tabstop=4 shiftwidth=4 expandtab: */