VirtualBox

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

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

Main/HostImpl: Solaris DVD enumeration fix for USB CD/DVD drives.

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