VirtualBox

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

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

Main/HostImpl: Solaris DVD enumeration, minor optimization.

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