VirtualBox

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

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

netadp: Re-create configured vboxnetX interfaces (#4213) on Linux

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

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