VirtualBox

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

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

Main: Some OS/2 build fixes.

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