VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostImpl.cpp@ 36128

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

Main/Metrics: Hypervisor and guest metrics re-done (#5566)

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