VirtualBox

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

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

Main/HostOnly: preserve vboxnetX with default address and mask (#4213)

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