VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostImpl.cpp@ 37952

Last change on this file since 37952 was 37307, checked in by vboxsync, 14 years ago

Partly revert r72058, the gcc warning was fixed already

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 101.0 KB
Line 
1/* $Id: HostImpl.cpp 37307 2011-06-02 12:48:21Z vboxsync $ */
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"
88extern "C" char *getfullrawname(char *);
89# endif
90# include "solaris/DynLoadLibSolaris.h"
91
92/**
93 * Solaris DVD drive list as returned by getDVDInfoFromDevTree().
94 */
95typedef 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. */
102typedef 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
125extern 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/x86.h>
154#include <VBox/vmm/hwacc_svm.h>
155#include <VBox/err.h>
156#include <VBox/settings.h>
157#include <VBox/sup.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
171struct 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
225HRESULT Host::FinalConstruct()
226{
227 return BaseFinalConstruct();
228}
229
230void Host::FinalRelease()
231{
232 uninit();
233 BaseFinalRelease();
234}
235
236/**
237 * Initializes the host object.
238 *
239 * @param aParent VirtualBox parent object.
240 */
241HRESULT 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 */
416void 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 */
468STDMETHODIMP 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 */
494STDMETHODIMP 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
518static 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 */
564STDMETHODIMP 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
747STDMETHODIMP 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
774STDMETHODIMP 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 */
809STDMETHODIMP 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 */
824STDMETHODIMP 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 */
839STDMETHODIMP 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 */
854STDMETHODIMP 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 */
870STDMETHODIMP 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 */
890STDMETHODIMP 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 */
934STDMETHODIMP 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 */
966STDMETHODIMP 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 */
988STDMETHODIMP 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 */
1010STDMETHODIMP 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 */
1029STDMETHODIMP 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 */
1065STDMETHODIMP 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
1076STDMETHODIMP 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
1089STDMETHODIMP Host::CreateHostOnlyNetworkInterface(IHostNetworkInterface **aHostNetworkInterface,
1090 IProgress **aProgress)
1091{
1092 CheckComArgOutPointerValid(aHostNetworkInterface);
1093 CheckComArgOutPointerValid(aProgress);
1094
1095 AutoCaller autoCaller(this);
1096 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1097
1098#ifdef VBOX_WITH_HOSTNETIF_API
1099 /* No need to lock anything. If there ever will - watch out, the function
1100 * called below grabs the VirtualBox lock. */
1101
1102 int r = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostNetworkInterface, aProgress);
1103 if (RT_SUCCESS(r))
1104 return S_OK;
1105
1106 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1107#else
1108 return E_NOTIMPL;
1109#endif
1110}
1111
1112STDMETHODIMP Host::RemoveHostOnlyNetworkInterface(IN_BSTR aId,
1113 IProgress **aProgress)
1114{
1115 CheckComArgOutPointerValid(aProgress);
1116
1117 AutoCaller autoCaller(this);
1118 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1119
1120#ifdef VBOX_WITH_HOSTNETIF_API
1121 /* No need to lock anything, the code below does not touch the state
1122 * of the host object. If that ever changes then check for lock order
1123 * violations with the called functions. */
1124
1125 Bstr name;
1126 HRESULT rc;
1127
1128 /* first check whether an interface with the given name already exists */
1129 {
1130 ComPtr<IHostNetworkInterface> iface;
1131 if (FAILED(FindHostNetworkInterfaceById(aId,
1132 iface.asOutParam())))
1133 return setError(VBOX_E_OBJECT_NOT_FOUND,
1134 tr("Host network interface with UUID {%RTuuid} does not exist"),
1135 Guid (aId).raw());
1136 rc = iface->COMGETTER(Name)(name.asOutParam());
1137 ComAssertComRCRet(rc, rc);
1138 }
1139
1140 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, Guid(aId).ref(), aProgress);
1141 if (RT_SUCCESS(r))
1142 {
1143 /* Drop configuration parameters for removed interface */
1144 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1145 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1146 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1147 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1148
1149 return S_OK;
1150 }
1151
1152 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1153#else
1154 return E_NOTIMPL;
1155#endif
1156}
1157
1158STDMETHODIMP Host::CreateUSBDeviceFilter(IN_BSTR aName,
1159 IHostUSBDeviceFilter **aFilter)
1160{
1161#ifdef VBOX_WITH_USB
1162 CheckComArgStrNotEmptyOrNull(aName);
1163 CheckComArgOutPointerValid(aFilter);
1164
1165 AutoCaller autoCaller(this);
1166 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1167
1168 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1169
1170 ComObjPtr<HostUSBDeviceFilter> filter;
1171 filter.createObject();
1172 HRESULT rc = filter->init(this, aName);
1173 ComAssertComRCRet(rc, rc);
1174 rc = filter.queryInterfaceTo(aFilter);
1175 AssertComRCReturn(rc, rc);
1176 return S_OK;
1177#else
1178 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1179 * extended error info to indicate that USB is simply not available
1180 * (w/o treating it as a failure), for example, as in OSE. */
1181 NOREF(aName);
1182 NOREF(aFilter);
1183 ReturnComNotImplemented();
1184#endif
1185}
1186
1187STDMETHODIMP Host::InsertUSBDeviceFilter(ULONG aPosition,
1188 IHostUSBDeviceFilter *aFilter)
1189{
1190#ifdef VBOX_WITH_USB
1191 CheckComArgNotNull(aFilter);
1192
1193 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1194 AutoCaller autoCaller(this);
1195 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1196
1197 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1198
1199 clearError();
1200 MultiResult rc = checkUSBProxyService();
1201 if (FAILED(rc)) return rc;
1202
1203 ComObjPtr<HostUSBDeviceFilter> pFilter;
1204 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1205 it != m->llChildren.end();
1206 ++it)
1207 {
1208 if (*it == aFilter)
1209 {
1210 pFilter = *it;
1211 break;
1212 }
1213 }
1214 if (pFilter.isNull())
1215 return setError(VBOX_E_INVALID_OBJECT_STATE,
1216 tr("The given USB device filter is not created within this VirtualBox instance"));
1217
1218 if (pFilter->mInList)
1219 return setError(E_INVALIDARG,
1220 tr("The given USB device filter is already in the list"));
1221
1222 /* iterate to the position... */
1223 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1224 std::advance(itPos, aPosition);
1225 /* ...and insert */
1226 m->llUSBDeviceFilters.insert(itPos, pFilter);
1227 pFilter->mInList = true;
1228
1229 /* notify the proxy (only when the filter is active) */
1230 if ( m->pUSBProxyService->isActive()
1231 && pFilter->getData().mActive)
1232 {
1233 ComAssertRet(pFilter->getId() == NULL, E_FAIL);
1234 pFilter->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1235 }
1236
1237 // save the global settings; for that we should hold only the VirtualBox lock
1238 alock.release();
1239 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1240 return rc = m->pParent->saveSettings();
1241#else
1242 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1243 * extended error info to indicate that USB is simply not available
1244 * (w/o treating it as a failure), for example, as in OSE. */
1245 NOREF(aPosition);
1246 NOREF(aFilter);
1247 ReturnComNotImplemented();
1248#endif
1249}
1250
1251STDMETHODIMP Host::RemoveUSBDeviceFilter(ULONG aPosition)
1252{
1253#ifdef VBOX_WITH_USB
1254
1255 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1256 AutoCaller autoCaller(this);
1257 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1258
1259 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1260
1261 clearError();
1262 MultiResult rc = checkUSBProxyService();
1263 if (FAILED(rc)) return rc;
1264
1265 if (!m->llUSBDeviceFilters.size())
1266 return setError(E_INVALIDARG,
1267 tr("The USB device filter list is empty"));
1268
1269 if (aPosition >= m->llUSBDeviceFilters.size())
1270 return setError(E_INVALIDARG,
1271 tr("Invalid position: %lu (must be in range [0, %lu])"),
1272 aPosition, m->llUSBDeviceFilters.size() - 1);
1273
1274 ComObjPtr<HostUSBDeviceFilter> filter;
1275 {
1276 /* iterate to the position... */
1277 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1278 std::advance (it, aPosition);
1279 /* ...get an element from there... */
1280 filter = *it;
1281 /* ...and remove */
1282 filter->mInList = false;
1283 m->llUSBDeviceFilters.erase(it);
1284 }
1285
1286 /* notify the proxy (only when the filter is active) */
1287 if (m->pUSBProxyService->isActive() && filter->getData().mActive)
1288 {
1289 ComAssertRet(filter->getId() != NULL, E_FAIL);
1290 m->pUSBProxyService->removeFilter(filter->getId());
1291 filter->getId() = NULL;
1292 }
1293
1294 // save the global settings; for that we should hold only the VirtualBox lock
1295 alock.release();
1296 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1297 return rc = m->pParent->saveSettings();
1298#else
1299 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1300 * extended error info to indicate that USB is simply not available
1301 * (w/o treating it as a failure), for example, as in OSE. */
1302 NOREF(aPosition);
1303 ReturnComNotImplemented();
1304#endif
1305}
1306
1307STDMETHODIMP Host::FindHostDVDDrive(IN_BSTR aName, IMedium **aDrive)
1308{
1309 CheckComArgStrNotEmptyOrNull(aName);
1310 CheckComArgOutPointerValid(aDrive);
1311
1312 ComObjPtr<Medium>medium;
1313 HRESULT rc = findHostDriveByNameOrId(DeviceType_DVD, Utf8Str(aName), medium);
1314 if (SUCCEEDED(rc))
1315 return medium.queryInterfaceTo(aDrive);
1316 else
1317 return setError(rc, Medium::tr("The host DVD drive named '%ls' could not be found"), aName);
1318}
1319
1320STDMETHODIMP Host::FindHostFloppyDrive(IN_BSTR aName, IMedium **aDrive)
1321{
1322 CheckComArgStrNotEmptyOrNull(aName);
1323 CheckComArgOutPointerValid(aDrive);
1324
1325 *aDrive = NULL;
1326
1327 ComObjPtr<Medium>medium;
1328 HRESULT rc = findHostDriveByNameOrId(DeviceType_Floppy, Utf8Str(aName), medium);
1329 if (SUCCEEDED(rc))
1330 return medium.queryInterfaceTo(aDrive);
1331 else
1332 return setError(rc, Medium::tr("The host floppy drive named '%ls' could not be found"), aName);
1333}
1334
1335STDMETHODIMP Host::FindHostNetworkInterfaceByName(IN_BSTR name, IHostNetworkInterface **networkInterface)
1336{
1337#ifndef VBOX_WITH_HOSTNETIF_API
1338 return E_NOTIMPL;
1339#else
1340 if (!name)
1341 return E_INVALIDARG;
1342 if (!networkInterface)
1343 return E_POINTER;
1344
1345 *networkInterface = NULL;
1346 ComObjPtr<HostNetworkInterface> found;
1347 std::list <ComObjPtr<HostNetworkInterface> > list;
1348 int rc = NetIfList(list);
1349 if (RT_FAILURE(rc))
1350 {
1351 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1352 return E_FAIL;
1353 }
1354 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1355 for (it = list.begin(); it != list.end(); ++it)
1356 {
1357 Bstr n;
1358 (*it)->COMGETTER(Name) (n.asOutParam());
1359 if (n == name)
1360 found = *it;
1361 }
1362
1363 if (!found)
1364 return setError(E_INVALIDARG,
1365 HostNetworkInterface::tr("The host network interface with the given name could not be found"));
1366
1367 found->setVirtualBox(m->pParent);
1368
1369 return found.queryInterfaceTo(networkInterface);
1370#endif
1371}
1372
1373STDMETHODIMP Host::FindHostNetworkInterfaceById(IN_BSTR id, IHostNetworkInterface **networkInterface)
1374{
1375#ifndef VBOX_WITH_HOSTNETIF_API
1376 return E_NOTIMPL;
1377#else
1378 if (Guid(id).isEmpty())
1379 return E_INVALIDARG;
1380 if (!networkInterface)
1381 return E_POINTER;
1382
1383 *networkInterface = NULL;
1384 ComObjPtr<HostNetworkInterface> found;
1385 std::list <ComObjPtr<HostNetworkInterface> > list;
1386 int rc = NetIfList(list);
1387 if (RT_FAILURE(rc))
1388 {
1389 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
1390 return E_FAIL;
1391 }
1392 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1393 for (it = list.begin(); it != list.end(); ++it)
1394 {
1395 Bstr g;
1396 (*it)->COMGETTER(Id) (g.asOutParam());
1397 if (g == id)
1398 found = *it;
1399 }
1400
1401 if (!found)
1402 return setError(E_INVALIDARG,
1403 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1404
1405 found->setVirtualBox(m->pParent);
1406
1407 return found.queryInterfaceTo(networkInterface);
1408#endif
1409}
1410
1411STDMETHODIMP Host::FindHostNetworkInterfacesOfType(HostNetworkInterfaceType_T type,
1412 ComSafeArrayOut(IHostNetworkInterface *, aNetworkInterfaces))
1413{
1414#ifdef VBOX_WITH_HOSTNETIF_API
1415 std::list <ComObjPtr<HostNetworkInterface> > allList;
1416 int rc = NetIfList(allList);
1417 if (RT_FAILURE(rc))
1418 return E_FAIL;
1419
1420 std::list <ComObjPtr<HostNetworkInterface> > resultList;
1421
1422 std::list <ComObjPtr<HostNetworkInterface> >::iterator it;
1423 for (it = allList.begin(); it != allList.end(); ++it)
1424 {
1425 HostNetworkInterfaceType_T t;
1426 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1427 if (FAILED(hr))
1428 return hr;
1429
1430 if (t == type)
1431 {
1432 (*it)->setVirtualBox(m->pParent);
1433 resultList.push_back (*it);
1434 }
1435 }
1436
1437 SafeIfaceArray<IHostNetworkInterface> filteredNetworkInterfaces (resultList);
1438 filteredNetworkInterfaces.detachTo(ComSafeArrayOutArg(aNetworkInterfaces));
1439
1440 return S_OK;
1441#else
1442 return E_NOTIMPL;
1443#endif
1444}
1445
1446STDMETHODIMP Host::FindUSBDeviceByAddress(IN_BSTR aAddress,
1447 IHostUSBDevice **aDevice)
1448{
1449#ifdef VBOX_WITH_USB
1450 CheckComArgStrNotEmptyOrNull(aAddress);
1451 CheckComArgOutPointerValid(aDevice);
1452
1453 *aDevice = NULL;
1454
1455 SafeIfaceArray<IHostUSBDevice> devsvec;
1456 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1457 if (FAILED(rc)) return rc;
1458
1459 for (size_t i = 0; i < devsvec.size(); ++i)
1460 {
1461 Bstr address;
1462 rc = devsvec[i]->COMGETTER(Address) (address.asOutParam());
1463 if (FAILED(rc)) return rc;
1464 if (address == aAddress)
1465 {
1466 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1467 }
1468 }
1469
1470 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1471 tr("Could not find a USB device with address '%ls'"),
1472 aAddress);
1473
1474#else /* !VBOX_WITH_USB */
1475 NOREF(aAddress);
1476 NOREF(aDevice);
1477 return E_NOTIMPL;
1478#endif /* !VBOX_WITH_USB */
1479}
1480
1481STDMETHODIMP Host::FindUSBDeviceById(IN_BSTR aId,
1482 IHostUSBDevice **aDevice)
1483{
1484#ifdef VBOX_WITH_USB
1485 CheckComArgExpr(aId, Guid (aId).isEmpty() == false);
1486 CheckComArgOutPointerValid(aDevice);
1487
1488 *aDevice = NULL;
1489
1490 SafeIfaceArray<IHostUSBDevice> devsvec;
1491 HRESULT rc = COMGETTER(USBDevices) (ComSafeArrayAsOutParam(devsvec));
1492 if (FAILED(rc)) return rc;
1493
1494 for (size_t i = 0; i < devsvec.size(); ++i)
1495 {
1496 Bstr id;
1497 rc = devsvec[i]->COMGETTER(Id) (id.asOutParam());
1498 if (FAILED(rc)) return rc;
1499 if (id == aId)
1500 {
1501 return ComObjPtr<IHostUSBDevice> (devsvec[i]).queryInterfaceTo(aDevice);
1502 }
1503 }
1504
1505 return setErrorNoLog (VBOX_E_OBJECT_NOT_FOUND, tr (
1506 "Could not find a USB device with uuid {%RTuuid}"),
1507 Guid (aId).raw());
1508
1509#else /* !VBOX_WITH_USB */
1510 NOREF(aId);
1511 NOREF(aDevice);
1512 return E_NOTIMPL;
1513#endif /* !VBOX_WITH_USB */
1514}
1515
1516STDMETHODIMP Host::GenerateMACAddress(BSTR *aAddress)
1517{
1518 CheckComArgOutPointerValid(aAddress);
1519 // no locking required
1520 Utf8Str mac;
1521 generateMACAddress(mac);
1522 Bstr(mac).cloneTo(aAddress);
1523 return S_OK;
1524}
1525
1526// public methods only for internal purposes
1527////////////////////////////////////////////////////////////////////////////////
1528
1529HRESULT Host::loadSettings(const settings::Host &data)
1530{
1531 HRESULT rc = S_OK;
1532#ifdef VBOX_WITH_USB
1533 AutoCaller autoCaller(this);
1534 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1535
1536 AutoMultiWriteLock2 alock(this->lockHandle(), &m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1537
1538 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
1539 it != data.llUSBDeviceFilters.end();
1540 ++it)
1541 {
1542 const settings::USBDeviceFilter &f = *it;
1543 ComObjPtr<HostUSBDeviceFilter> pFilter;
1544 pFilter.createObject();
1545 rc = pFilter->init(this, f);
1546 if (FAILED(rc)) break;
1547
1548 m->llUSBDeviceFilters.push_back(pFilter);
1549 pFilter->mInList = true;
1550
1551 /* notify the proxy (only when the filter is active) */
1552 if (pFilter->getData().mActive)
1553 {
1554 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
1555 flt->getId() = m->pUSBProxyService->insertFilter(&pFilter->getData().mUSBFilter);
1556 }
1557 }
1558#else
1559 NOREF(data);
1560#endif /* VBOX_WITH_USB */
1561 return rc;
1562}
1563
1564HRESULT Host::saveSettings(settings::Host &data)
1565{
1566#ifdef VBOX_WITH_USB
1567 AutoCaller autoCaller(this);
1568 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1569
1570 AutoReadLock alock1(this COMMA_LOCKVAL_SRC_POS);
1571 AutoReadLock alock2(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1572
1573 data.llUSBDeviceFilters.clear();
1574
1575 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
1576 it != m->llUSBDeviceFilters.end();
1577 ++it)
1578 {
1579 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
1580 settings::USBDeviceFilter f;
1581 pFilter->saveSettings(f);
1582 data.llUSBDeviceFilters.push_back(f);
1583 }
1584#else
1585 NOREF(data);
1586#endif /* VBOX_WITH_USB */
1587
1588 return S_OK;
1589}
1590
1591/**
1592 * Sets the given pointer to point to the static list of DVD or floppy
1593 * drives in the Host instance data, depending on the @a mediumType
1594 * parameter.
1595 *
1596 * This builds the list on the first call; it adds or removes host drives
1597 * that may have changed if fRefresh == true.
1598 *
1599 * The caller must hold the m->drivesLock write lock before calling this.
1600 * To protect the list to which the caller's pointer points, the caller
1601 * must also hold that lock.
1602 *
1603 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
1604 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
1605 * @param pll Caller's pointer which gets set to the static list of host drives.
1606 * @return
1607 */
1608HRESULT Host::getDrives(DeviceType_T mediumType,
1609 bool fRefresh,
1610 MediaList *&pll)
1611{
1612 HRESULT rc = S_OK;
1613 Assert(m->drivesLock.isWriteLockOnCurrentThread());
1614
1615 MediaList llNew;
1616 MediaList *pllCached;
1617 bool *pfListBuilt = NULL;
1618
1619 switch (mediumType)
1620 {
1621 case DeviceType_DVD:
1622 if (!m->fDVDDrivesListBuilt || fRefresh)
1623 {
1624 rc = buildDVDDrivesList(llNew);
1625 if (FAILED(rc))
1626 return rc;
1627 pfListBuilt = &m->fDVDDrivesListBuilt;
1628 }
1629 pllCached = &m->llDVDDrives;
1630 break;
1631
1632 case DeviceType_Floppy:
1633 if (!m->fFloppyDrivesListBuilt || fRefresh)
1634 {
1635 rc = buildFloppyDrivesList(llNew);
1636 if (FAILED(rc))
1637 return rc;
1638 pfListBuilt = &m->fFloppyDrivesListBuilt;
1639 }
1640 pllCached = &m->llFloppyDrives;
1641 break;
1642
1643 default:
1644 return E_INVALIDARG;
1645 }
1646
1647 if (pfListBuilt)
1648 {
1649 // a list was built in llNew above:
1650 if (!*pfListBuilt)
1651 {
1652 // this was the first call (instance bool is still false): then just copy the whole list and return
1653 *pllCached = llNew;
1654 // and mark the instance data as "built"
1655 *pfListBuilt = true;
1656 }
1657 else
1658 {
1659 // list was built, and this was a subsequent call: then compare the old and the new lists
1660
1661 // remove drives from the cached list which are no longer present
1662 for (MediaList::iterator itCached = pllCached->begin();
1663 itCached != pllCached->end();
1664 /*nothing */)
1665 {
1666 Medium *pCached = *itCached;
1667 const Utf8Str strLocationCached = pCached->getLocationFull();
1668 bool fFound = false;
1669 for (MediaList::iterator itNew = llNew.begin();
1670 itNew != llNew.end();
1671 ++itNew)
1672 {
1673 Medium *pNew = *itNew;
1674 const Utf8Str strLocationNew = pNew->getLocationFull();
1675 if (strLocationNew == strLocationCached)
1676 {
1677 fFound = true;
1678 break;
1679 }
1680 }
1681 if (!fFound)
1682 itCached = pllCached->erase(itCached);
1683 else
1684 ++itCached;
1685 }
1686
1687 // add drives to the cached list that are not on there yet
1688 for (MediaList::iterator itNew = llNew.begin();
1689 itNew != llNew.end();
1690 ++itNew)
1691 {
1692 Medium *pNew = *itNew;
1693 const Utf8Str strLocationNew = pNew->getLocationFull();
1694 bool fFound = false;
1695 for (MediaList::iterator itCached = pllCached->begin();
1696 itCached != pllCached->end();
1697 ++itCached)
1698 {
1699 Medium *pCached = *itCached;
1700 const Utf8Str strLocationCached = pCached->getLocationFull();
1701 if (strLocationNew == strLocationCached)
1702 {
1703 fFound = true;
1704 break;
1705 }
1706 }
1707
1708 if (!fFound)
1709 pllCached->push_back(pNew);
1710 }
1711 }
1712 }
1713
1714 // return cached list to caller
1715 pll = pllCached;
1716
1717 return rc;
1718}
1719
1720/**
1721 * Goes through the list of host drives that would be returned by getDrives()
1722 * and looks for a host drive with the given UUID. If found, it sets pMedium
1723 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1724 *
1725 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1726 * @param uuid Medium UUID of host drive to look for.
1727 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1728 * @param pMedium Medium object, if found…
1729 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1730 */
1731HRESULT Host::findHostDriveById(DeviceType_T mediumType,
1732 const Guid &uuid,
1733 bool fRefresh,
1734 ComObjPtr<Medium> &pMedium)
1735{
1736 MediaList *pllMedia;
1737
1738 AutoWriteLock wlock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
1739 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1740 if (SUCCEEDED(rc))
1741 {
1742 for (MediaList::iterator it = pllMedia->begin();
1743 it != pllMedia->end();
1744 ++it)
1745 {
1746 Medium *pThis = *it;
1747 AutoCaller mediumCaller(pThis);
1748 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1749 if (pThis->getId() == uuid)
1750 {
1751 pMedium = pThis;
1752 return S_OK;
1753 }
1754 }
1755 }
1756
1757 return VBOX_E_OBJECT_NOT_FOUND;
1758}
1759
1760/**
1761 * Goes through the list of host drives that would be returned by getDrives()
1762 * and looks for a host drive with the given name. If found, it sets pMedium
1763 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1764 *
1765 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1766 * @param strLocationFull Name (path) of host drive to look for.
1767 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1768 * @param pMedium Medium object, if found…
1769 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1770 */
1771HRESULT Host::findHostDriveByName(DeviceType_T mediumType,
1772 const Utf8Str &strLocationFull,
1773 bool fRefresh,
1774 ComObjPtr<Medium> &pMedium)
1775{
1776 MediaList *pllMedia;
1777
1778 AutoWriteLock wlock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
1779 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1780 if (SUCCEEDED(rc))
1781 {
1782 for (MediaList::iterator it = pllMedia->begin();
1783 it != pllMedia->end();
1784 ++it)
1785 {
1786 Medium *pThis = *it;
1787 AutoCaller mediumCaller(pThis);
1788 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1789 if (pThis->getLocationFull() == strLocationFull)
1790 {
1791 pMedium = pThis;
1792 return S_OK;
1793 }
1794 }
1795 }
1796
1797 return VBOX_E_OBJECT_NOT_FOUND;
1798}
1799
1800/**
1801 * Goes through the list of host drives that would be returned by getDrives()
1802 * and looks for a host drive with the given name, location or ID. If found,
1803 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1804 *
1805 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1806 * @param strNameOrId Name or full location or UUID of host drive to look for.
1807 * @param pMedium Medium object, if found…
1808 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1809 */
1810HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType,
1811 const Utf8Str &strNameOrId,
1812 ComObjPtr<Medium> &pMedium)
1813{
1814 AutoWriteLock wlock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
1815
1816 Guid uuid(strNameOrId);
1817 if (!uuid.isEmpty())
1818 return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
1819
1820 // string is not a syntactically valid UUID: try a name then
1821 return findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
1822}
1823
1824/**
1825 * Called from getDrives() to build the DVD drives list.
1826 * @param pll
1827 * @return
1828 */
1829HRESULT Host::buildDVDDrivesList(MediaList &list)
1830{
1831 HRESULT rc = S_OK;
1832
1833 Assert(m->drivesLock.isWriteLockOnCurrentThread());
1834
1835 try
1836 {
1837#if defined(RT_OS_WINDOWS)
1838 int sz = GetLogicalDriveStrings(0, NULL);
1839 TCHAR *hostDrives = new TCHAR[sz+1];
1840 GetLogicalDriveStrings(sz, hostDrives);
1841 wchar_t driveName[3] = { '?', ':', '\0' };
1842 TCHAR *p = hostDrives;
1843 do
1844 {
1845 if (GetDriveType(p) == DRIVE_CDROM)
1846 {
1847 driveName[0] = *p;
1848 ComObjPtr<Medium> hostDVDDriveObj;
1849 hostDVDDriveObj.createObject();
1850 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1851 list.push_back(hostDVDDriveObj);
1852 }
1853 p += _tcslen(p) + 1;
1854 }
1855 while (*p);
1856 delete[] hostDrives;
1857
1858#elif defined(RT_OS_SOLARIS)
1859# ifdef VBOX_USE_LIBHAL
1860 if (!getDVDInfoFromHal(list))
1861# endif
1862 {
1863 getDVDInfoFromDevTree(list);
1864 }
1865
1866#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1867 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1868 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1869 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1870 {
1871 ComObjPtr<Medium> hostDVDDriveObj;
1872 Utf8Str location(it->mDevice);
1873 Utf8Str description(it->mDescription);
1874 if (SUCCEEDED(rc))
1875 rc = hostDVDDriveObj.createObject();
1876 if (SUCCEEDED(rc))
1877 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1878 if (SUCCEEDED(rc))
1879 list.push_back(hostDVDDriveObj);
1880 }
1881#elif defined(RT_OS_DARWIN)
1882 PDARWINDVD cur = DarwinGetDVDDrives();
1883 while (cur)
1884 {
1885 ComObjPtr<Medium> hostDVDDriveObj;
1886 hostDVDDriveObj.createObject();
1887 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
1888 list.push_back(hostDVDDriveObj);
1889
1890 /* next */
1891 void *freeMe = cur;
1892 cur = cur->pNext;
1893 RTMemFree(freeMe);
1894 }
1895#else
1896 /* PORTME */
1897#endif
1898 }
1899 catch(std::bad_alloc &)
1900 {
1901 rc = E_OUTOFMEMORY;
1902 }
1903 return rc;
1904}
1905
1906/**
1907 * Called from getDrives() to build the floppy drives list.
1908 * @param list
1909 * @return
1910 */
1911HRESULT Host::buildFloppyDrivesList(MediaList &list)
1912{
1913 HRESULT rc = S_OK;
1914
1915 Assert(m->drivesLock.isWriteLockOnCurrentThread());
1916
1917 try
1918 {
1919#ifdef RT_OS_WINDOWS
1920 int sz = GetLogicalDriveStrings(0, NULL);
1921 TCHAR *hostDrives = new TCHAR[sz+1];
1922 GetLogicalDriveStrings(sz, hostDrives);
1923 wchar_t driveName[3] = { '?', ':', '\0' };
1924 TCHAR *p = hostDrives;
1925 do
1926 {
1927 if (GetDriveType(p) == DRIVE_REMOVABLE)
1928 {
1929 driveName[0] = *p;
1930 ComObjPtr<Medium> hostFloppyDriveObj;
1931 hostFloppyDriveObj.createObject();
1932 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
1933 list.push_back(hostFloppyDriveObj);
1934 }
1935 p += _tcslen(p) + 1;
1936 }
1937 while (*p);
1938 delete[] hostDrives;
1939#elif defined(RT_OS_LINUX)
1940 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
1941 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
1942 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
1943 {
1944 ComObjPtr<Medium> hostFloppyDriveObj;
1945 Utf8Str location(it->mDevice);
1946 Utf8Str description(it->mDescription);
1947 if (SUCCEEDED(rc))
1948 rc = hostFloppyDriveObj.createObject();
1949 if (SUCCEEDED(rc))
1950 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
1951 if (SUCCEEDED(rc))
1952 list.push_back(hostFloppyDriveObj);
1953 }
1954#else
1955 NOREF(list);
1956 /* PORTME */
1957#endif
1958 }
1959 catch(std::bad_alloc &)
1960 {
1961 rc = E_OUTOFMEMORY;
1962 }
1963
1964 return rc;
1965}
1966
1967#ifdef VBOX_WITH_USB
1968USBProxyService* Host::usbProxyService()
1969{
1970 return m->pUSBProxyService;
1971}
1972
1973HRESULT Host::addChild(HostUSBDeviceFilter *pChild)
1974{
1975 AutoCaller autoCaller(this);
1976 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1977
1978 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1979
1980 m->llChildren.push_back(pChild);
1981
1982 return S_OK;
1983}
1984
1985HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
1986{
1987 AutoCaller autoCaller(this);
1988 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1989
1990 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1991
1992 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1993 it != m->llChildren.end();
1994 ++it)
1995 {
1996 if (*it == pChild)
1997 {
1998 m->llChildren.erase(it);
1999 break;
2000 }
2001 }
2002
2003 return S_OK;
2004}
2005
2006VirtualBox* Host::parent()
2007{
2008 return m->pParent;
2009}
2010
2011/**
2012 * Called by setter methods of all USB device filters.
2013 */
2014HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2015 BOOL aActiveChanged /* = FALSE */)
2016{
2017 AutoCaller autoCaller(this);
2018 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2019
2020 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2021
2022 if (aFilter->mInList)
2023 {
2024 if (aActiveChanged)
2025 {
2026 // insert/remove the filter from the proxy
2027 if (aFilter->getData().mActive)
2028 {
2029 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
2030 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2031 }
2032 else
2033 {
2034 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2035 m->pUSBProxyService->removeFilter(aFilter->getId());
2036 aFilter->getId() = NULL;
2037 }
2038 }
2039 else
2040 {
2041 if (aFilter->getData().mActive)
2042 {
2043 // update the filter in the proxy
2044 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2045 m->pUSBProxyService->removeFilter(aFilter->getId());
2046 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2047 }
2048 }
2049
2050 // save the global settings... yeah, on every single filter property change
2051 // for that we should hold only the VirtualBox lock
2052 alock.release();
2053 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2054 return m->pParent->saveSettings();
2055 }
2056
2057 return S_OK;
2058}
2059
2060
2061/**
2062 * Interface for obtaining a copy of the USBDeviceFilterList,
2063 * used by the USBProxyService.
2064 *
2065 * @param aGlobalFilters Where to put the global filter list copy.
2066 * @param aMachines Where to put the machine vector.
2067 */
2068void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2069{
2070 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
2071
2072 *aGlobalFilters = m->llUSBDeviceFilters;
2073}
2074
2075#endif /* VBOX_WITH_USB */
2076
2077// private methods
2078////////////////////////////////////////////////////////////////////////////////
2079
2080#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2081
2082/**
2083 * Helper function to get the slice number from a device path
2084 *
2085 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2086 * @returns Pointer to the slice portion of the given path.
2087 */
2088static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2089{
2090 char *pszFound = NULL;
2091 char *pszSlice = strrchr(pszDevLinkPath, 's');
2092 char *pszDisk = strrchr(pszDevLinkPath, 'd');
2093 if (pszSlice && pszSlice > pszDisk)
2094 pszFound = pszSlice;
2095 else
2096 pszFound = pszDisk;
2097
2098 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2099 return pszFound;
2100
2101 return NULL;
2102}
2103
2104/**
2105 * Walk device links and returns an allocated path for the first one in the snapshot.
2106 *
2107 * @param DevLink Handle to the device link being walked.
2108 * @param pvArg Opaque data containing the pointer to the path.
2109 * @returns Pointer to an allocated device path string.
2110 */
2111static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2112{
2113 char **ppszPath = (char **)pvArg;
2114 *ppszPath = strdup(di_devlink_path(DevLink));
2115 return DI_WALK_TERMINATE;
2116}
2117
2118/**
2119 * Walk all devices in the system and enumerate CD/DVD drives.
2120 * @param Node Handle to the current node.
2121 * @param pvArg Opaque data (holds list pointer).
2122 * @returns Solaris specific code whether to continue walking or not.
2123 */
2124static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2125{
2126 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2127
2128 /*
2129 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2130 * As unfortunately the Solaris drivers only export these common properties.
2131 */
2132 int *pInt = NULL;
2133 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2134 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2135 {
2136 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2137 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2138 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2139 {
2140 char *pszProduct = NULL;
2141 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2142 {
2143 char *pszVendor = NULL;
2144 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2145 {
2146 /*
2147 * Found a DVD drive, we need to scan the minor nodes to find the correct
2148 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2149 */
2150 int Major = di_driver_major(Node);
2151 di_minor_t Minor = DI_MINOR_NIL;
2152 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2153 if (DevLink)
2154 {
2155 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2156 {
2157 dev_t Dev = di_minor_devt(Minor);
2158 if ( Major != (int)major(Dev)
2159 || di_minor_spectype(Minor) == S_IFBLK
2160 || di_minor_type(Minor) != DDM_MINOR)
2161 {
2162 continue;
2163 }
2164
2165 char *pszMinorPath = di_devfs_minor_path(Minor);
2166 if (!pszMinorPath)
2167 continue;
2168
2169 char *pszDevLinkPath = NULL;
2170 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2171 di_devfs_path_free(pszMinorPath);
2172
2173 if (pszDevLinkPath)
2174 {
2175 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2176 if ( pszSlice && !strcmp(pszSlice, "s2")
2177 && !strncmp(pszDevLinkPath, "/dev/rdsk", sizeof("/dev/rdsk") - 1)) /* We want only raw disks */
2178 {
2179 /*
2180 * We've got a fully qualified DVD drive. Add it to the list.
2181 */
2182 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2183 if (RT_LIKELY(pDrive))
2184 {
2185 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2186 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2187 if (*ppDrives)
2188 pDrive->pNext = *ppDrives;
2189 *ppDrives = pDrive;
2190
2191 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2192 free(pszDevLinkPath);
2193 break;
2194 }
2195 }
2196 free(pszDevLinkPath);
2197 }
2198 }
2199 di_devlink_fini(&DevLink);
2200 }
2201 }
2202 }
2203 }
2204 }
2205 return DI_WALK_CONTINUE;
2206}
2207
2208/**
2209 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2210 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2211 */
2212void Host::getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2213{
2214 PSOLARISDVD pDrives = NULL;
2215 di_node_t RootNode = di_init("/", DINFOCPYALL);
2216 if (RootNode != DI_NODE_NIL)
2217 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2218
2219 di_fini(RootNode);
2220
2221 while (pDrives)
2222 {
2223 ComObjPtr<Medium> hostDVDDriveObj;
2224 hostDVDDriveObj.createObject();
2225 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2226 list.push_back(hostDVDDriveObj);
2227
2228 void *pvDrive = pDrives;
2229 pDrives = pDrives->pNext;
2230 RTMemFree(pvDrive);
2231 }
2232}
2233
2234/* Solaris hosts, loading libhal at runtime */
2235
2236/**
2237 * Helper function to query the hal subsystem for information about DVD drives attached to the
2238 * system.
2239 *
2240 * @returns true if information was successfully obtained, false otherwise
2241 * @retval list drives found will be attached to this list
2242 */
2243bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2244{
2245 bool halSuccess = false;
2246 DBusError dbusError;
2247 if (!gLibHalCheckPresence())
2248 return false;
2249 gDBusErrorInit (&dbusError);
2250 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2251 if (dbusConnection != 0)
2252 {
2253 LibHalContext *halContext = gLibHalCtxNew();
2254 if (halContext != 0)
2255 {
2256 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2257 {
2258 if (gLibHalCtxInit(halContext, &dbusError))
2259 {
2260 int numDevices;
2261 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2262 "storage.drive_type", "cdrom",
2263 &numDevices, &dbusError);
2264 if (halDevices != 0)
2265 {
2266 /* Hal is installed and working, so if no devices are reported, assume
2267 that there are none. */
2268 halSuccess = true;
2269 for (int i = 0; i < numDevices; i++)
2270 {
2271 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2272 halDevices[i], "block.device", &dbusError);
2273#ifdef RT_OS_SOLARIS
2274 /* The CD/DVD ioctls work only for raw device nodes. */
2275 char *tmp = getfullrawname(devNode);
2276 gLibHalFreeString(devNode);
2277 devNode = tmp;
2278#endif
2279
2280 if (devNode != 0)
2281 {
2282// if (validateDevice(devNode, true))
2283// {
2284 Utf8Str description;
2285 char *vendor, *product;
2286 /* We do not check the error here, as this field may
2287 not even exist. */
2288 vendor = gLibHalDeviceGetPropertyString(halContext,
2289 halDevices[i], "info.vendor", 0);
2290 product = gLibHalDeviceGetPropertyString(halContext,
2291 halDevices[i], "info.product", &dbusError);
2292 if ((product != 0 && product[0] != 0))
2293 {
2294 if ((vendor != 0) && (vendor[0] != 0))
2295 {
2296 description = Utf8StrFmt ("%s %s",
2297 vendor, product);
2298 }
2299 else
2300 {
2301 description = product;
2302 }
2303 ComObjPtr<Medium> hostDVDDriveObj;
2304 hostDVDDriveObj.createObject();
2305 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2306 Bstr(devNode), Bstr(description));
2307 list.push_back (hostDVDDriveObj);
2308 }
2309 else
2310 {
2311 if (product == 0)
2312 {
2313 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2314 halDevices[i], dbusError.name, dbusError.message));
2315 gDBusErrorFree(&dbusError);
2316 }
2317 ComObjPtr<Medium> hostDVDDriveObj;
2318 hostDVDDriveObj.createObject();
2319 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2320 Bstr(devNode));
2321 list.push_back (hostDVDDriveObj);
2322 }
2323 if (vendor != 0)
2324 {
2325 gLibHalFreeString(vendor);
2326 }
2327 if (product != 0)
2328 {
2329 gLibHalFreeString(product);
2330 }
2331// }
2332// else
2333// {
2334// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2335// }
2336#ifndef RT_OS_SOLARIS
2337 gLibHalFreeString(devNode);
2338#else
2339 free(devNode);
2340#endif
2341 }
2342 else
2343 {
2344 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2345 halDevices[i], dbusError.name, dbusError.message));
2346 gDBusErrorFree(&dbusError);
2347 }
2348 }
2349 gLibHalFreeStringArray(halDevices);
2350 }
2351 else
2352 {
2353 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2354 gDBusErrorFree(&dbusError);
2355 }
2356 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2357 {
2358 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2359 gDBusErrorFree(&dbusError);
2360 }
2361 }
2362 else
2363 {
2364 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2365 gDBusErrorFree(&dbusError);
2366 }
2367 gLibHalCtxFree(halContext);
2368 }
2369 else
2370 {
2371 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
2372 }
2373 }
2374 else
2375 {
2376 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2377 }
2378 gDBusConnectionUnref(dbusConnection);
2379 }
2380 else
2381 {
2382 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2383 gDBusErrorFree(&dbusError);
2384 }
2385 return halSuccess;
2386}
2387
2388
2389/**
2390 * Helper function to query the hal subsystem for information about floppy drives attached to the
2391 * system.
2392 *
2393 * @returns true if information was successfully obtained, false otherwise
2394 * @retval list drives found will be attached to this list
2395 */
2396bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2397{
2398 bool halSuccess = false;
2399 DBusError dbusError;
2400 if (!gLibHalCheckPresence())
2401 return false;
2402 gDBusErrorInit (&dbusError);
2403 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2404 if (dbusConnection != 0)
2405 {
2406 LibHalContext *halContext = gLibHalCtxNew();
2407 if (halContext != 0)
2408 {
2409 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2410 {
2411 if (gLibHalCtxInit(halContext, &dbusError))
2412 {
2413 int numDevices;
2414 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2415 "storage.drive_type", "floppy",
2416 &numDevices, &dbusError);
2417 if (halDevices != 0)
2418 {
2419 /* Hal is installed and working, so if no devices are reported, assume
2420 that there are none. */
2421 halSuccess = true;
2422 for (int i = 0; i < numDevices; i++)
2423 {
2424 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2425 halDevices[i], "storage.drive_type", 0);
2426 if (driveType != 0)
2427 {
2428 if (strcmp(driveType, "floppy") != 0)
2429 {
2430 gLibHalFreeString(driveType);
2431 continue;
2432 }
2433 gLibHalFreeString(driveType);
2434 }
2435 else
2436 {
2437 /* An error occurred. The attribute "storage.drive_type"
2438 probably didn't exist. */
2439 continue;
2440 }
2441 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2442 halDevices[i], "block.device", &dbusError);
2443 if (devNode != 0)
2444 {
2445// if (validateDevice(devNode, false))
2446// {
2447 Utf8Str description;
2448 char *vendor, *product;
2449 /* We do not check the error here, as this field may
2450 not even exist. */
2451 vendor = gLibHalDeviceGetPropertyString(halContext,
2452 halDevices[i], "info.vendor", 0);
2453 product = gLibHalDeviceGetPropertyString(halContext,
2454 halDevices[i], "info.product", &dbusError);
2455 if ((product != 0) && (product[0] != 0))
2456 {
2457 if ((vendor != 0) && (vendor[0] != 0))
2458 {
2459 description = Utf8StrFmt ("%s %s",
2460 vendor, product);
2461 }
2462 else
2463 {
2464 description = product;
2465 }
2466 ComObjPtr<Medium> hostFloppyDrive;
2467 hostFloppyDrive.createObject();
2468 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2469 Bstr(devNode), Bstr(description));
2470 list.push_back (hostFloppyDrive);
2471 }
2472 else
2473 {
2474 if (product == 0)
2475 {
2476 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2477 halDevices[i], dbusError.name, dbusError.message));
2478 gDBusErrorFree(&dbusError);
2479 }
2480 ComObjPtr<Medium> hostFloppyDrive;
2481 hostFloppyDrive.createObject();
2482 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2483 Bstr(devNode));
2484 list.push_back (hostFloppyDrive);
2485 }
2486 if (vendor != 0)
2487 {
2488 gLibHalFreeString(vendor);
2489 }
2490 if (product != 0)
2491 {
2492 gLibHalFreeString(product);
2493 }
2494// }
2495// else
2496// {
2497// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2498// }
2499 gLibHalFreeString(devNode);
2500 }
2501 else
2502 {
2503 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2504 halDevices[i], dbusError.name, dbusError.message));
2505 gDBusErrorFree(&dbusError);
2506 }
2507 }
2508 gLibHalFreeStringArray(halDevices);
2509 }
2510 else
2511 {
2512 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2513 gDBusErrorFree(&dbusError);
2514 }
2515 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2516 {
2517 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2518 gDBusErrorFree(&dbusError);
2519 }
2520 }
2521 else
2522 {
2523 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2524 gDBusErrorFree(&dbusError);
2525 }
2526 gLibHalCtxFree(halContext);
2527 }
2528 else
2529 {
2530 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2531 }
2532 }
2533 else
2534 {
2535 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2536 }
2537 gDBusConnectionUnref(dbusConnection);
2538 }
2539 else
2540 {
2541 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2542 gDBusErrorFree(&dbusError);
2543 }
2544 return halSuccess;
2545}
2546#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2547
2548/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2549#if defined(RT_OS_SOLARIS)
2550
2551/**
2552 * Helper function to parse the given mount file and add found entries
2553 */
2554void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2555{
2556#ifdef RT_OS_LINUX
2557 FILE *mtab = setmntent(mountTable, "r");
2558 if (mtab)
2559 {
2560 struct mntent *mntent;
2561 char *mnt_type;
2562 char *mnt_dev;
2563 char *tmp;
2564 while ((mntent = getmntent(mtab)))
2565 {
2566 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2567 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2568 strcpy(mnt_type, mntent->mnt_type);
2569 strcpy(mnt_dev, mntent->mnt_fsname);
2570 // supermount fs case
2571 if (strcmp(mnt_type, "supermount") == 0)
2572 {
2573 tmp = strstr(mntent->mnt_opts, "fs=");
2574 if (tmp)
2575 {
2576 free(mnt_type);
2577 mnt_type = strdup(tmp + strlen("fs="));
2578 if (mnt_type)
2579 {
2580 tmp = strchr(mnt_type, ',');
2581 if (tmp)
2582 *tmp = '\0';
2583 }
2584 }
2585 tmp = strstr(mntent->mnt_opts, "dev=");
2586 if (tmp)
2587 {
2588 free(mnt_dev);
2589 mnt_dev = strdup(tmp + strlen("dev="));
2590 if (mnt_dev)
2591 {
2592 tmp = strchr(mnt_dev, ',');
2593 if (tmp)
2594 *tmp = '\0';
2595 }
2596 }
2597 }
2598 // use strstr here to cover things fs types like "udf,iso9660"
2599 if (strstr(mnt_type, "iso9660") == 0)
2600 {
2601 /** @todo check whether we've already got the drive in our list! */
2602 if (validateDevice(mnt_dev, true))
2603 {
2604 ComObjPtr<Medium> hostDVDDriveObj;
2605 hostDVDDriveObj.createObject();
2606 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2607 list.push_back (hostDVDDriveObj);
2608 }
2609 }
2610 free(mnt_dev);
2611 free(mnt_type);
2612 }
2613 endmntent(mtab);
2614 }
2615#else // RT_OS_SOLARIS
2616 FILE *mntFile = fopen(mountTable, "r");
2617 if (mntFile)
2618 {
2619 struct mnttab mntTab;
2620 while (getmntent(mntFile, &mntTab) == 0)
2621 {
2622 const char *mountName = mntTab.mnt_special;
2623 const char *mountPoint = mntTab.mnt_mountp;
2624 const char *mountFSType = mntTab.mnt_fstype;
2625 if (mountName && mountPoint && mountFSType)
2626 {
2627 // skip devices we are not interested in
2628 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2629 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2630 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2631 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2632 {
2633 char *rawDevName = getfullrawname((char *)mountName);
2634 if (validateDevice(rawDevName, true))
2635 {
2636 ComObjPtr<Medium> hostDVDDriveObj;
2637 hostDVDDriveObj.createObject();
2638 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2639 list.push_back (hostDVDDriveObj);
2640 }
2641 free(rawDevName);
2642 }
2643 }
2644 }
2645
2646 fclose(mntFile);
2647 }
2648#endif
2649}
2650
2651/**
2652 * Helper function to check whether the given device node is a valid drive
2653 */
2654bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2655{
2656 struct stat statInfo;
2657 bool retValue = false;
2658
2659 // sanity check
2660 if (!deviceNode)
2661 {
2662 return false;
2663 }
2664
2665 // first a simple stat() call
2666 if (stat(deviceNode, &statInfo) < 0)
2667 {
2668 return false;
2669 }
2670 else
2671 {
2672 if (isCDROM)
2673 {
2674 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2675 {
2676 int fileHandle;
2677 // now try to open the device
2678 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2679 if (fileHandle >= 0)
2680 {
2681 cdrom_subchnl cdChannelInfo;
2682 cdChannelInfo.cdsc_format = CDROM_MSF;
2683 // this call will finally reveal the whole truth
2684#ifdef RT_OS_LINUX
2685 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2686 (errno == EIO) || (errno == ENOENT) ||
2687 (errno == EINVAL) || (errno == ENOMEDIUM))
2688#else
2689 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2690 (errno == EIO) || (errno == ENOENT) ||
2691 (errno == EINVAL))
2692#endif
2693 {
2694 retValue = true;
2695 }
2696 close(fileHandle);
2697 }
2698 }
2699 } else
2700 {
2701 // floppy case
2702 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2703 {
2704 /// @todo do some more testing, maybe a nice IOCTL!
2705 retValue = true;
2706 }
2707 }
2708 }
2709 return retValue;
2710}
2711#endif // RT_OS_SOLARIS
2712
2713#ifdef VBOX_WITH_USB
2714/**
2715 * Checks for the presence and status of the USB Proxy Service.
2716 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2717 * warning) if the proxy service is not available due to the way the host is
2718 * configured (at present, that means that usbfs and hal/DBus are not
2719 * available on a Linux host) or E_FAIL and a corresponding error message
2720 * otherwise. Intended to be used by methods that rely on the Proxy Service
2721 * availability.
2722 *
2723 * @note This method may return a warning result code. It is recommended to use
2724 * MultiError to store the return value.
2725 *
2726 * @note Locks this object for reading.
2727 */
2728HRESULT Host::checkUSBProxyService()
2729{
2730 AutoCaller autoCaller(this);
2731 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2732
2733 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2734
2735 AssertReturn(m->pUSBProxyService, E_FAIL);
2736 if (!m->pUSBProxyService->isActive())
2737 {
2738 /* disable the USB controller completely to avoid assertions if the
2739 * USB proxy service could not start. */
2740
2741 switch (m->pUSBProxyService->getLastError())
2742 {
2743 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
2744 return setWarning(E_FAIL,
2745 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
2746 case VERR_VUSB_USB_DEVICE_PERMISSION:
2747 return setWarning(E_FAIL,
2748 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"));
2749 case VERR_VUSB_USBFS_PERMISSION:
2750 return setWarning(E_FAIL,
2751 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"));
2752 case VINF_SUCCESS:
2753 return setWarning(E_FAIL,
2754 tr("The USB Proxy Service has not yet been ported to this host"));
2755 default:
2756 return setWarning (E_FAIL, "%s: %Rrc",
2757 tr ("Could not load the Host USB Proxy service"),
2758 m->pUSBProxyService->getLastError());
2759 }
2760 }
2761
2762 return S_OK;
2763}
2764#endif /* VBOX_WITH_USB */
2765
2766#ifdef VBOX_WITH_RESOURCE_USAGE_API
2767
2768void Host::registerMetrics(PerformanceCollector *aCollector)
2769{
2770 pm::CollectorHAL *hal = aCollector->getHAL();
2771 /* Create sub metrics */
2772 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
2773 "Percentage of processor time spent in user mode.");
2774 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
2775 "Percentage of processor time spent in kernel mode.");
2776 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
2777 "Percentage of processor time spent idling.");
2778 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
2779 "Average of current frequency of all processors.");
2780 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
2781 "Total physical memory installed.");
2782 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
2783 "Physical memory currently occupied.");
2784 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
2785 "Physical memory currently available to applications.");
2786 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
2787 "Total physical memory used by the hypervisor.");
2788 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
2789 "Total physical memory free inside the hypervisor.");
2790 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
2791 "Total physical memory ballooned by the hypervisor.");
2792 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
2793 "Total physical memory shared between VMs.");
2794
2795
2796 /* Create and register base metrics */
2797 IUnknown *objptr;
2798 ComObjPtr<Host> tmp = this;
2799 tmp.queryInterfaceTo(&objptr);
2800 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
2801 cpuLoadIdle);
2802 aCollector->registerBaseMetric (cpuLoad);
2803 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
2804 aCollector->registerBaseMetric (cpuMhz);
2805 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr,
2806 ramUsageTotal,
2807 ramUsageUsed,
2808 ramUsageFree);
2809 aCollector->registerBaseMetric (ramUsage);
2810 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), objptr,
2811 ramVMMUsed,
2812 ramVMMFree,
2813 ramVMMBallooned,
2814 ramVMMShared);
2815 aCollector->registerBaseMetric (ramVmm);
2816
2817 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
2818 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2819 new pm::AggregateAvg()));
2820 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2821 new pm::AggregateMin()));
2822 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2823 new pm::AggregateMax()));
2824
2825 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2826 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2827 new pm::AggregateAvg()));
2828 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2829 new pm::AggregateMin()));
2830 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2831 new pm::AggregateMax()));
2832
2833 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2834 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2835 new pm::AggregateAvg()));
2836 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2837 new pm::AggregateMin()));
2838 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2839 new pm::AggregateMax()));
2840
2841 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
2842 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2843 new pm::AggregateAvg()));
2844 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2845 new pm::AggregateMin()));
2846 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2847 new pm::AggregateMax()));
2848
2849 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
2850 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2851 new pm::AggregateAvg()));
2852 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2853 new pm::AggregateMin()));
2854 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2855 new pm::AggregateMax()));
2856
2857 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
2858 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2859 new pm::AggregateAvg()));
2860 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2861 new pm::AggregateMin()));
2862 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2863 new pm::AggregateMax()));
2864
2865 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
2866 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2867 new pm::AggregateAvg()));
2868 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2869 new pm::AggregateMin()));
2870 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2871 new pm::AggregateMax()));
2872
2873 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
2874 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2875 new pm::AggregateAvg()));
2876 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2877 new pm::AggregateMin()));
2878 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2879 new pm::AggregateMax()));
2880
2881 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
2882 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2883 new pm::AggregateAvg()));
2884 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2885 new pm::AggregateMin()));
2886 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2887 new pm::AggregateMax()));
2888
2889 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
2890 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2891 new pm::AggregateAvg()));
2892 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2893 new pm::AggregateMin()));
2894 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2895 new pm::AggregateMax()));
2896
2897 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
2898 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2899 new pm::AggregateAvg()));
2900 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2901 new pm::AggregateMin()));
2902 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2903 new pm::AggregateMax()));
2904}
2905
2906void Host::unregisterMetrics (PerformanceCollector *aCollector)
2907{
2908 aCollector->unregisterMetricsFor(this);
2909 aCollector->unregisterBaseMetricsFor(this);
2910}
2911
2912
2913/* static */
2914void Host::generateMACAddress(Utf8Str &mac)
2915{
2916 /*
2917 * Our strategy is as follows: the first three bytes are our fixed
2918 * vendor ID (080027). The remaining 3 bytes will be taken from the
2919 * start of a GUID. This is a fairly safe algorithm.
2920 */
2921 Guid guid;
2922 guid.create();
2923 mac = Utf8StrFmt("080027%02X%02X%02X",
2924 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
2925}
2926
2927#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2928
2929/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette