VirtualBox

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

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

Main/Host: fix scoping to avoid compiler warning about variable aliasing

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