VirtualBox

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

Last change on this file since 28479 was 28456, checked in by vboxsync, 15 years ago

solaris build fix

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

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