VirtualBox

source: vbox/trunk/src/VBox/Main/HostImpl.cpp@ 31570

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

Main: Lock order when saving host usb filters.

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

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