VirtualBox

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

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

Main/idl: new method IHost::generateMACAddress, including implementation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 100.7 KB
Line 
1/* $Id: HostImpl.cpp 36615 2011-04-07 12:45:27Z 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 ++itCached)
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 }
1683
1684 // add drives to the cached list that are not on there yet
1685 for (MediaList::iterator itNew = llNew.begin();
1686 itNew != llNew.end();
1687 ++itNew)
1688 {
1689 Medium *pNew = *itNew;
1690 const Utf8Str strLocationNew = pNew->getLocationFull();
1691 bool fFound = false;
1692 for (MediaList::iterator itCached = pllCached->begin();
1693 itCached != pllCached->end();
1694 ++itCached)
1695 {
1696 Medium *pCached = *itCached;
1697 const Utf8Str strLocationCached = pCached->getLocationFull();
1698 if (strLocationNew == strLocationCached)
1699 {
1700 fFound = true;
1701 break;
1702 }
1703 }
1704
1705 if (!fFound)
1706 pllCached->push_back(pNew);
1707 }
1708 }
1709 }
1710
1711 // return cached list to caller
1712 pll = pllCached;
1713
1714 return rc;
1715}
1716
1717/**
1718 * Goes through the list of host drives that would be returned by getDrives()
1719 * and looks for a host drive with the given UUID. If found, it sets pMedium
1720 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1721 *
1722 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1723 * @param uuid Medium UUID of host drive to look for.
1724 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1725 * @param pMedium Medium object, if found…
1726 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1727 */
1728HRESULT Host::findHostDriveById(DeviceType_T mediumType,
1729 const Guid &uuid,
1730 bool fRefresh,
1731 ComObjPtr<Medium> &pMedium)
1732{
1733 MediaList *pllMedia;
1734
1735 AutoWriteLock wlock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
1736 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1737 if (SUCCEEDED(rc))
1738 {
1739 for (MediaList::iterator it = pllMedia->begin();
1740 it != pllMedia->end();
1741 ++it)
1742 {
1743 Medium *pThis = *it;
1744 AutoCaller mediumCaller(pThis);
1745 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1746 if (pThis->getId() == uuid)
1747 {
1748 pMedium = pThis;
1749 return S_OK;
1750 }
1751 }
1752 }
1753
1754 return VBOX_E_OBJECT_NOT_FOUND;
1755}
1756
1757/**
1758 * Goes through the list of host drives that would be returned by getDrives()
1759 * and looks for a host drive with the given name. If found, it sets pMedium
1760 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1761 *
1762 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1763 * @param strLocationFull Name (path) of host drive to look for.
1764 * @param fRefresh Whether to refresh the host drives list (see getDrives())
1765 * @param pMedium Medium object, if found…
1766 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1767 */
1768HRESULT Host::findHostDriveByName(DeviceType_T mediumType,
1769 const Utf8Str &strLocationFull,
1770 bool fRefresh,
1771 ComObjPtr<Medium> &pMedium)
1772{
1773 MediaList *pllMedia;
1774
1775 AutoWriteLock wlock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
1776 HRESULT rc = getDrives(mediumType, fRefresh, pllMedia);
1777 if (SUCCEEDED(rc))
1778 {
1779 for (MediaList::iterator it = pllMedia->begin();
1780 it != pllMedia->end();
1781 ++it)
1782 {
1783 Medium *pThis = *it;
1784 AutoCaller mediumCaller(pThis);
1785 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
1786 if (pThis->getLocationFull() == strLocationFull)
1787 {
1788 pMedium = pThis;
1789 return S_OK;
1790 }
1791 }
1792 }
1793
1794 return VBOX_E_OBJECT_NOT_FOUND;
1795}
1796
1797/**
1798 * Goes through the list of host drives that would be returned by getDrives()
1799 * and looks for a host drive with the given name, location or ID. If found,
1800 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
1801 *
1802 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
1803 * @param strNameOrId Name or full location or UUID of host drive to look for.
1804 * @param pMedium Medium object, if found…
1805 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
1806 */
1807HRESULT Host::findHostDriveByNameOrId(DeviceType_T mediumType,
1808 const Utf8Str &strNameOrId,
1809 ComObjPtr<Medium> &pMedium)
1810{
1811 AutoWriteLock wlock(m->drivesLock COMMA_LOCKVAL_SRC_POS);
1812
1813 Guid uuid(strNameOrId);
1814 if (!uuid.isEmpty())
1815 return findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
1816
1817 // string is not a syntactically valid UUID: try a name then
1818 return findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
1819}
1820
1821/**
1822 * Called from getDrives() to build the DVD drives list.
1823 * @param pll
1824 * @return
1825 */
1826HRESULT Host::buildDVDDrivesList(MediaList &list)
1827{
1828 HRESULT rc = S_OK;
1829
1830 Assert(m->drivesLock.isWriteLockOnCurrentThread());
1831
1832 try
1833 {
1834#if defined(RT_OS_WINDOWS)
1835 int sz = GetLogicalDriveStrings(0, NULL);
1836 TCHAR *hostDrives = new TCHAR[sz+1];
1837 GetLogicalDriveStrings(sz, hostDrives);
1838 wchar_t driveName[3] = { '?', ':', '\0' };
1839 TCHAR *p = hostDrives;
1840 do
1841 {
1842 if (GetDriveType(p) == DRIVE_CDROM)
1843 {
1844 driveName[0] = *p;
1845 ComObjPtr<Medium> hostDVDDriveObj;
1846 hostDVDDriveObj.createObject();
1847 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
1848 list.push_back(hostDVDDriveObj);
1849 }
1850 p += _tcslen(p) + 1;
1851 }
1852 while (*p);
1853 delete[] hostDrives;
1854
1855#elif defined(RT_OS_SOLARIS)
1856# ifdef VBOX_USE_LIBHAL
1857 if (!getDVDInfoFromHal(list))
1858# endif
1859 {
1860 getDVDInfoFromDevTree(list);
1861 }
1862
1863#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
1864 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
1865 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
1866 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
1867 {
1868 ComObjPtr<Medium> hostDVDDriveObj;
1869 Utf8Str location(it->mDevice);
1870 Utf8Str description(it->mDescription);
1871 if (SUCCEEDED(rc))
1872 rc = hostDVDDriveObj.createObject();
1873 if (SUCCEEDED(rc))
1874 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
1875 if (SUCCEEDED(rc))
1876 list.push_back(hostDVDDriveObj);
1877 }
1878#elif defined(RT_OS_DARWIN)
1879 PDARWINDVD cur = DarwinGetDVDDrives();
1880 while (cur)
1881 {
1882 ComObjPtr<Medium> hostDVDDriveObj;
1883 hostDVDDriveObj.createObject();
1884 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
1885 list.push_back(hostDVDDriveObj);
1886
1887 /* next */
1888 void *freeMe = cur;
1889 cur = cur->pNext;
1890 RTMemFree(freeMe);
1891 }
1892#else
1893 /* PORTME */
1894#endif
1895 }
1896 catch(std::bad_alloc &)
1897 {
1898 rc = E_OUTOFMEMORY;
1899 }
1900 return rc;
1901}
1902
1903/**
1904 * Called from getDrives() to build the floppy drives list.
1905 * @param list
1906 * @return
1907 */
1908HRESULT Host::buildFloppyDrivesList(MediaList &list)
1909{
1910 HRESULT rc = S_OK;
1911
1912 Assert(m->drivesLock.isWriteLockOnCurrentThread());
1913
1914 try
1915 {
1916#ifdef RT_OS_WINDOWS
1917 int sz = GetLogicalDriveStrings(0, NULL);
1918 TCHAR *hostDrives = new TCHAR[sz+1];
1919 GetLogicalDriveStrings(sz, hostDrives);
1920 wchar_t driveName[3] = { '?', ':', '\0' };
1921 TCHAR *p = hostDrives;
1922 do
1923 {
1924 if (GetDriveType(p) == DRIVE_REMOVABLE)
1925 {
1926 driveName[0] = *p;
1927 ComObjPtr<Medium> hostFloppyDriveObj;
1928 hostFloppyDriveObj.createObject();
1929 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
1930 list.push_back(hostFloppyDriveObj);
1931 }
1932 p += _tcslen(p) + 1;
1933 }
1934 while (*p);
1935 delete[] hostDrives;
1936#elif defined(RT_OS_LINUX)
1937 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
1938 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
1939 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
1940 {
1941 ComObjPtr<Medium> hostFloppyDriveObj;
1942 Utf8Str location(it->mDevice);
1943 Utf8Str description(it->mDescription);
1944 if (SUCCEEDED(rc))
1945 rc = hostFloppyDriveObj.createObject();
1946 if (SUCCEEDED(rc))
1947 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
1948 if (SUCCEEDED(rc))
1949 list.push_back(hostFloppyDriveObj);
1950 }
1951#else
1952 NOREF(list);
1953 /* PORTME */
1954#endif
1955 }
1956 catch(std::bad_alloc &)
1957 {
1958 rc = E_OUTOFMEMORY;
1959 }
1960
1961 return rc;
1962}
1963
1964#ifdef VBOX_WITH_USB
1965USBProxyService* Host::usbProxyService()
1966{
1967 return m->pUSBProxyService;
1968}
1969
1970HRESULT Host::addChild(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 m->llChildren.push_back(pChild);
1978
1979 return S_OK;
1980}
1981
1982HRESULT Host::removeChild(HostUSBDeviceFilter *pChild)
1983{
1984 AutoCaller autoCaller(this);
1985 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1986
1987 AutoWriteLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
1988
1989 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1990 it != m->llChildren.end();
1991 ++it)
1992 {
1993 if (*it == pChild)
1994 {
1995 m->llChildren.erase(it);
1996 break;
1997 }
1998 }
1999
2000 return S_OK;
2001}
2002
2003VirtualBox* Host::parent()
2004{
2005 return m->pParent;
2006}
2007
2008/**
2009 * Called by setter methods of all USB device filters.
2010 */
2011HRESULT Host::onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2012 BOOL aActiveChanged /* = FALSE */)
2013{
2014 AutoCaller autoCaller(this);
2015 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2016
2017 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2018
2019 if (aFilter->mInList)
2020 {
2021 if (aActiveChanged)
2022 {
2023 // insert/remove the filter from the proxy
2024 if (aFilter->getData().mActive)
2025 {
2026 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
2027 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2028 }
2029 else
2030 {
2031 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2032 m->pUSBProxyService->removeFilter(aFilter->getId());
2033 aFilter->getId() = NULL;
2034 }
2035 }
2036 else
2037 {
2038 if (aFilter->getData().mActive)
2039 {
2040 // update the filter in the proxy
2041 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
2042 m->pUSBProxyService->removeFilter(aFilter->getId());
2043 aFilter->getId() = m->pUSBProxyService->insertFilter(&aFilter->getData().mUSBFilter);
2044 }
2045 }
2046
2047 // save the global settings... yeah, on every single filter property change
2048 // for that we should hold only the VirtualBox lock
2049 alock.release();
2050 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2051 return m->pParent->saveSettings();
2052 }
2053
2054 return S_OK;
2055}
2056
2057
2058/**
2059 * Interface for obtaining a copy of the USBDeviceFilterList,
2060 * used by the USBProxyService.
2061 *
2062 * @param aGlobalFilters Where to put the global filter list copy.
2063 * @param aMachines Where to put the machine vector.
2064 */
2065void Host::getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2066{
2067 AutoReadLock alock(&m->usbListsLock COMMA_LOCKVAL_SRC_POS);
2068
2069 *aGlobalFilters = m->llUSBDeviceFilters;
2070}
2071
2072#endif /* VBOX_WITH_USB */
2073
2074// private methods
2075////////////////////////////////////////////////////////////////////////////////
2076
2077#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2078
2079/**
2080 * Helper function to get the slice number from a device path
2081 *
2082 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2083 * @returns Pointer to the slice portion of the given path.
2084 */
2085static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2086{
2087 char *pszFound = NULL;
2088 char *pszSlice = strrchr(pszDevLinkPath, 's');
2089 char *pszDisk = strrchr(pszDevLinkPath, 'd');
2090 if (pszSlice && pszSlice > pszDisk)
2091 pszFound = pszSlice;
2092 else
2093 pszFound = pszDisk;
2094
2095 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2096 return pszFound;
2097
2098 return NULL;
2099}
2100
2101/**
2102 * Walk device links and returns an allocated path for the first one in the snapshot.
2103 *
2104 * @param DevLink Handle to the device link being walked.
2105 * @param pvArg Opaque data containing the pointer to the path.
2106 * @returns Pointer to an allocated device path string.
2107 */
2108static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2109{
2110 char **ppszPath = (char **)pvArg;
2111 *ppszPath = strdup(di_devlink_path(DevLink));
2112 return DI_WALK_TERMINATE;
2113}
2114
2115/**
2116 * Walk all devices in the system and enumerate CD/DVD drives.
2117 * @param Node Handle to the current node.
2118 * @param pvArg Opaque data (holds list pointer).
2119 * @returns Solaris specific code whether to continue walking or not.
2120 */
2121static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2122{
2123 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2124
2125 /*
2126 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2127 * As unfortunately the Solaris drivers only export these common properties.
2128 */
2129 int *pInt = NULL;
2130 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2131 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2132 {
2133 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2134 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2135 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2136 {
2137 char *pszProduct = NULL;
2138 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2139 {
2140 char *pszVendor = NULL;
2141 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2142 {
2143 /*
2144 * Found a DVD drive, we need to scan the minor nodes to find the correct
2145 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2146 */
2147 int Major = di_driver_major(Node);
2148 di_minor_t Minor = DI_MINOR_NIL;
2149 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2150 if (DevLink)
2151 {
2152 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2153 {
2154 dev_t Dev = di_minor_devt(Minor);
2155 if ( Major != (int)major(Dev)
2156 || di_minor_spectype(Minor) == S_IFBLK
2157 || di_minor_type(Minor) != DDM_MINOR)
2158 {
2159 continue;
2160 }
2161
2162 char *pszMinorPath = di_devfs_minor_path(Minor);
2163 if (!pszMinorPath)
2164 continue;
2165
2166 char *pszDevLinkPath = NULL;
2167 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2168 di_devfs_path_free(pszMinorPath);
2169
2170 if (pszDevLinkPath)
2171 {
2172 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2173 if ( pszSlice && !strcmp(pszSlice, "s2")
2174 && !strncmp(pszDevLinkPath, "/dev/rdsk", sizeof("/dev/rdsk") - 1)) /* We want only raw disks */
2175 {
2176 /*
2177 * We've got a fully qualified DVD drive. Add it to the list.
2178 */
2179 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2180 if (RT_LIKELY(pDrive))
2181 {
2182 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2183 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2184 if (*ppDrives)
2185 pDrive->pNext = *ppDrives;
2186 *ppDrives = pDrive;
2187
2188 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2189 free(pszDevLinkPath);
2190 break;
2191 }
2192 }
2193 free(pszDevLinkPath);
2194 }
2195 }
2196 di_devlink_fini(&DevLink);
2197 }
2198 }
2199 }
2200 }
2201 }
2202 return DI_WALK_CONTINUE;
2203}
2204
2205/**
2206 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2207 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2208 */
2209void Host::getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2210{
2211 PSOLARISDVD pDrives = NULL;
2212 di_node_t RootNode = di_init("/", DINFOCPYALL);
2213 if (RootNode != DI_NODE_NIL)
2214 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2215
2216 di_fini(RootNode);
2217
2218 while (pDrives)
2219 {
2220 ComObjPtr<Medium> hostDVDDriveObj;
2221 hostDVDDriveObj.createObject();
2222 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2223 list.push_back(hostDVDDriveObj);
2224
2225 void *pvDrive = pDrives;
2226 pDrives = pDrives->pNext;
2227 RTMemFree(pvDrive);
2228 }
2229}
2230
2231/* Solaris hosts, loading libhal at runtime */
2232
2233/**
2234 * Helper function to query the hal subsystem for information about DVD drives attached to the
2235 * system.
2236 *
2237 * @returns true if information was successfully obtained, false otherwise
2238 * @retval list drives found will be attached to this list
2239 */
2240bool Host::getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2241{
2242 bool halSuccess = false;
2243 DBusError dbusError;
2244 if (!gLibHalCheckPresence())
2245 return false;
2246 gDBusErrorInit (&dbusError);
2247 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2248 if (dbusConnection != 0)
2249 {
2250 LibHalContext *halContext = gLibHalCtxNew();
2251 if (halContext != 0)
2252 {
2253 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2254 {
2255 if (gLibHalCtxInit(halContext, &dbusError))
2256 {
2257 int numDevices;
2258 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2259 "storage.drive_type", "cdrom",
2260 &numDevices, &dbusError);
2261 if (halDevices != 0)
2262 {
2263 /* Hal is installed and working, so if no devices are reported, assume
2264 that there are none. */
2265 halSuccess = true;
2266 for (int i = 0; i < numDevices; i++)
2267 {
2268 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2269 halDevices[i], "block.device", &dbusError);
2270#ifdef RT_OS_SOLARIS
2271 /* The CD/DVD ioctls work only for raw device nodes. */
2272 char *tmp = getfullrawname(devNode);
2273 gLibHalFreeString(devNode);
2274 devNode = tmp;
2275#endif
2276
2277 if (devNode != 0)
2278 {
2279// if (validateDevice(devNode, true))
2280// {
2281 Utf8Str description;
2282 char *vendor, *product;
2283 /* We do not check the error here, as this field may
2284 not even exist. */
2285 vendor = gLibHalDeviceGetPropertyString(halContext,
2286 halDevices[i], "info.vendor", 0);
2287 product = gLibHalDeviceGetPropertyString(halContext,
2288 halDevices[i], "info.product", &dbusError);
2289 if ((product != 0 && product[0] != 0))
2290 {
2291 if ((vendor != 0) && (vendor[0] != 0))
2292 {
2293 description = Utf8StrFmt ("%s %s",
2294 vendor, product);
2295 }
2296 else
2297 {
2298 description = product;
2299 }
2300 ComObjPtr<Medium> hostDVDDriveObj;
2301 hostDVDDriveObj.createObject();
2302 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2303 Bstr(devNode), Bstr(description));
2304 list.push_back (hostDVDDriveObj);
2305 }
2306 else
2307 {
2308 if (product == 0)
2309 {
2310 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2311 halDevices[i], dbusError.name, dbusError.message));
2312 gDBusErrorFree(&dbusError);
2313 }
2314 ComObjPtr<Medium> hostDVDDriveObj;
2315 hostDVDDriveObj.createObject();
2316 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2317 Bstr(devNode));
2318 list.push_back (hostDVDDriveObj);
2319 }
2320 if (vendor != 0)
2321 {
2322 gLibHalFreeString(vendor);
2323 }
2324 if (product != 0)
2325 {
2326 gLibHalFreeString(product);
2327 }
2328// }
2329// else
2330// {
2331// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2332// }
2333#ifndef RT_OS_SOLARIS
2334 gLibHalFreeString(devNode);
2335#else
2336 free(devNode);
2337#endif
2338 }
2339 else
2340 {
2341 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2342 halDevices[i], dbusError.name, dbusError.message));
2343 gDBusErrorFree(&dbusError);
2344 }
2345 }
2346 gLibHalFreeStringArray(halDevices);
2347 }
2348 else
2349 {
2350 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2351 gDBusErrorFree(&dbusError);
2352 }
2353 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2354 {
2355 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2356 gDBusErrorFree(&dbusError);
2357 }
2358 }
2359 else
2360 {
2361 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2362 gDBusErrorFree(&dbusError);
2363 }
2364 gLibHalCtxFree(halContext);
2365 }
2366 else
2367 {
2368 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
2369 }
2370 }
2371 else
2372 {
2373 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
2374 }
2375 gDBusConnectionUnref(dbusConnection);
2376 }
2377 else
2378 {
2379 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2380 gDBusErrorFree(&dbusError);
2381 }
2382 return halSuccess;
2383}
2384
2385
2386/**
2387 * Helper function to query the hal subsystem for information about floppy drives attached to the
2388 * system.
2389 *
2390 * @returns true if information was successfully obtained, false otherwise
2391 * @retval list drives found will be attached to this list
2392 */
2393bool Host::getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
2394{
2395 bool halSuccess = false;
2396 DBusError dbusError;
2397 if (!gLibHalCheckPresence())
2398 return false;
2399 gDBusErrorInit (&dbusError);
2400 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2401 if (dbusConnection != 0)
2402 {
2403 LibHalContext *halContext = gLibHalCtxNew();
2404 if (halContext != 0)
2405 {
2406 if (gLibHalCtxSetDBusConnection (halContext, dbusConnection))
2407 {
2408 if (gLibHalCtxInit(halContext, &dbusError))
2409 {
2410 int numDevices;
2411 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2412 "storage.drive_type", "floppy",
2413 &numDevices, &dbusError);
2414 if (halDevices != 0)
2415 {
2416 /* Hal is installed and working, so if no devices are reported, assume
2417 that there are none. */
2418 halSuccess = true;
2419 for (int i = 0; i < numDevices; i++)
2420 {
2421 char *driveType = gLibHalDeviceGetPropertyString(halContext,
2422 halDevices[i], "storage.drive_type", 0);
2423 if (driveType != 0)
2424 {
2425 if (strcmp(driveType, "floppy") != 0)
2426 {
2427 gLibHalFreeString(driveType);
2428 continue;
2429 }
2430 gLibHalFreeString(driveType);
2431 }
2432 else
2433 {
2434 /* An error occurred. The attribute "storage.drive_type"
2435 probably didn't exist. */
2436 continue;
2437 }
2438 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2439 halDevices[i], "block.device", &dbusError);
2440 if (devNode != 0)
2441 {
2442// if (validateDevice(devNode, false))
2443// {
2444 Utf8Str description;
2445 char *vendor, *product;
2446 /* We do not check the error here, as this field may
2447 not even exist. */
2448 vendor = gLibHalDeviceGetPropertyString(halContext,
2449 halDevices[i], "info.vendor", 0);
2450 product = gLibHalDeviceGetPropertyString(halContext,
2451 halDevices[i], "info.product", &dbusError);
2452 if ((product != 0) && (product[0] != 0))
2453 {
2454 if ((vendor != 0) && (vendor[0] != 0))
2455 {
2456 description = Utf8StrFmt ("%s %s",
2457 vendor, product);
2458 }
2459 else
2460 {
2461 description = product;
2462 }
2463 ComObjPtr<Medium> hostFloppyDrive;
2464 hostFloppyDrive.createObject();
2465 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2466 Bstr(devNode), Bstr(description));
2467 list.push_back (hostFloppyDrive);
2468 }
2469 else
2470 {
2471 if (product == 0)
2472 {
2473 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2474 halDevices[i], dbusError.name, dbusError.message));
2475 gDBusErrorFree(&dbusError);
2476 }
2477 ComObjPtr<Medium> hostFloppyDrive;
2478 hostFloppyDrive.createObject();
2479 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
2480 Bstr(devNode));
2481 list.push_back (hostFloppyDrive);
2482 }
2483 if (vendor != 0)
2484 {
2485 gLibHalFreeString(vendor);
2486 }
2487 if (product != 0)
2488 {
2489 gLibHalFreeString(product);
2490 }
2491// }
2492// else
2493// {
2494// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
2495// }
2496 gLibHalFreeString(devNode);
2497 }
2498 else
2499 {
2500 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
2501 halDevices[i], dbusError.name, dbusError.message));
2502 gDBusErrorFree(&dbusError);
2503 }
2504 }
2505 gLibHalFreeStringArray(halDevices);
2506 }
2507 else
2508 {
2509 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2510 gDBusErrorFree(&dbusError);
2511 }
2512 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
2513 {
2514 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2515 gDBusErrorFree(&dbusError);
2516 }
2517 }
2518 else
2519 {
2520 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2521 gDBusErrorFree(&dbusError);
2522 }
2523 gLibHalCtxFree(halContext);
2524 }
2525 else
2526 {
2527 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
2528 }
2529 }
2530 else
2531 {
2532 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
2533 }
2534 gDBusConnectionUnref(dbusConnection);
2535 }
2536 else
2537 {
2538 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
2539 gDBusErrorFree(&dbusError);
2540 }
2541 return halSuccess;
2542}
2543#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
2544
2545/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
2546#if defined(RT_OS_SOLARIS)
2547
2548/**
2549 * Helper function to parse the given mount file and add found entries
2550 */
2551void Host::parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
2552{
2553#ifdef RT_OS_LINUX
2554 FILE *mtab = setmntent(mountTable, "r");
2555 if (mtab)
2556 {
2557 struct mntent *mntent;
2558 char *mnt_type;
2559 char *mnt_dev;
2560 char *tmp;
2561 while ((mntent = getmntent(mtab)))
2562 {
2563 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
2564 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
2565 strcpy(mnt_type, mntent->mnt_type);
2566 strcpy(mnt_dev, mntent->mnt_fsname);
2567 // supermount fs case
2568 if (strcmp(mnt_type, "supermount") == 0)
2569 {
2570 tmp = strstr(mntent->mnt_opts, "fs=");
2571 if (tmp)
2572 {
2573 free(mnt_type);
2574 mnt_type = strdup(tmp + strlen("fs="));
2575 if (mnt_type)
2576 {
2577 tmp = strchr(mnt_type, ',');
2578 if (tmp)
2579 *tmp = '\0';
2580 }
2581 }
2582 tmp = strstr(mntent->mnt_opts, "dev=");
2583 if (tmp)
2584 {
2585 free(mnt_dev);
2586 mnt_dev = strdup(tmp + strlen("dev="));
2587 if (mnt_dev)
2588 {
2589 tmp = strchr(mnt_dev, ',');
2590 if (tmp)
2591 *tmp = '\0';
2592 }
2593 }
2594 }
2595 // use strstr here to cover things fs types like "udf,iso9660"
2596 if (strstr(mnt_type, "iso9660") == 0)
2597 {
2598 /** @todo check whether we've already got the drive in our list! */
2599 if (validateDevice(mnt_dev, true))
2600 {
2601 ComObjPtr<Medium> hostDVDDriveObj;
2602 hostDVDDriveObj.createObject();
2603 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
2604 list.push_back (hostDVDDriveObj);
2605 }
2606 }
2607 free(mnt_dev);
2608 free(mnt_type);
2609 }
2610 endmntent(mtab);
2611 }
2612#else // RT_OS_SOLARIS
2613 FILE *mntFile = fopen(mountTable, "r");
2614 if (mntFile)
2615 {
2616 struct mnttab mntTab;
2617 while (getmntent(mntFile, &mntTab) == 0)
2618 {
2619 const char *mountName = mntTab.mnt_special;
2620 const char *mountPoint = mntTab.mnt_mountp;
2621 const char *mountFSType = mntTab.mnt_fstype;
2622 if (mountName && mountPoint && mountFSType)
2623 {
2624 // skip devices we are not interested in
2625 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts, proc, fd, swap)
2626 (*mountFSType && (strncmp(mountFSType, "devfs", 5) != 0 && // skip devfs (i.e. /devices)
2627 strncmp(mountFSType, "dev", 3) != 0 && // skip dev (i.e. /dev)
2628 strncmp(mountFSType, "lofs", 4) != 0))) // skip loop-back file-system (lofs)
2629 {
2630 char *rawDevName = getfullrawname((char *)mountName);
2631 if (validateDevice(rawDevName, true))
2632 {
2633 ComObjPtr<Medium> hostDVDDriveObj;
2634 hostDVDDriveObj.createObject();
2635 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
2636 list.push_back (hostDVDDriveObj);
2637 }
2638 free(rawDevName);
2639 }
2640 }
2641 }
2642
2643 fclose(mntFile);
2644 }
2645#endif
2646}
2647
2648/**
2649 * Helper function to check whether the given device node is a valid drive
2650 */
2651bool Host::validateDevice(const char *deviceNode, bool isCDROM)
2652{
2653 struct stat statInfo;
2654 bool retValue = false;
2655
2656 // sanity check
2657 if (!deviceNode)
2658 {
2659 return false;
2660 }
2661
2662 // first a simple stat() call
2663 if (stat(deviceNode, &statInfo) < 0)
2664 {
2665 return false;
2666 }
2667 else
2668 {
2669 if (isCDROM)
2670 {
2671 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2672 {
2673 int fileHandle;
2674 // now try to open the device
2675 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
2676 if (fileHandle >= 0)
2677 {
2678 cdrom_subchnl cdChannelInfo;
2679 cdChannelInfo.cdsc_format = CDROM_MSF;
2680 // this call will finally reveal the whole truth
2681#ifdef RT_OS_LINUX
2682 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2683 (errno == EIO) || (errno == ENOENT) ||
2684 (errno == EINVAL) || (errno == ENOMEDIUM))
2685#else
2686 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
2687 (errno == EIO) || (errno == ENOENT) ||
2688 (errno == EINVAL))
2689#endif
2690 {
2691 retValue = true;
2692 }
2693 close(fileHandle);
2694 }
2695 }
2696 } else
2697 {
2698 // floppy case
2699 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
2700 {
2701 /// @todo do some more testing, maybe a nice IOCTL!
2702 retValue = true;
2703 }
2704 }
2705 }
2706 return retValue;
2707}
2708#endif // RT_OS_SOLARIS
2709
2710#ifdef VBOX_WITH_USB
2711/**
2712 * Checks for the presence and status of the USB Proxy Service.
2713 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
2714 * warning) if the proxy service is not available due to the way the host is
2715 * configured (at present, that means that usbfs and hal/DBus are not
2716 * available on a Linux host) or E_FAIL and a corresponding error message
2717 * otherwise. Intended to be used by methods that rely on the Proxy Service
2718 * availability.
2719 *
2720 * @note This method may return a warning result code. It is recommended to use
2721 * MultiError to store the return value.
2722 *
2723 * @note Locks this object for reading.
2724 */
2725HRESULT Host::checkUSBProxyService()
2726{
2727 AutoCaller autoCaller(this);
2728 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2729
2730 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2731
2732 AssertReturn(m->pUSBProxyService, E_FAIL);
2733 if (!m->pUSBProxyService->isActive())
2734 {
2735 /* disable the USB controller completely to avoid assertions if the
2736 * USB proxy service could not start. */
2737
2738 if (m->pUSBProxyService->getLastError() == VERR_FILE_NOT_FOUND)
2739 return setWarning(E_FAIL,
2740 tr("Could not load the Host USB Proxy Service (%Rrc). The service might not be installed on the host computer"),
2741 m->pUSBProxyService->getLastError());
2742 if (m->pUSBProxyService->getLastError() == VINF_SUCCESS)
2743#ifdef RT_OS_LINUX
2744 return setWarning (VBOX_E_HOST_ERROR,
2745# ifdef VBOX_WITH_DBUS
2746 tr ("The USB Proxy Service could not be started, because neither the USB file system (usbfs) nor the hardware information service (hal) is available")
2747# else
2748 tr ("The USB Proxy Service could not be started, because the USB file system (usbfs) is not available")
2749# endif
2750 );
2751#else /* !RT_OS_LINUX */
2752 return setWarning (E_FAIL,
2753 tr ("The USB Proxy Service has not yet been ported to this host"));
2754#endif /* !RT_OS_LINUX */
2755 return setWarning (E_FAIL,
2756 tr ("Could not load the Host USB Proxy service (%Rrc)"),
2757 m->pUSBProxyService->getLastError());
2758 }
2759
2760 return S_OK;
2761}
2762#endif /* VBOX_WITH_USB */
2763
2764#ifdef VBOX_WITH_RESOURCE_USAGE_API
2765
2766void Host::registerMetrics(PerformanceCollector *aCollector)
2767{
2768 pm::CollectorHAL *hal = aCollector->getHAL();
2769 /* Create sub metrics */
2770 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
2771 "Percentage of processor time spent in user mode.");
2772 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
2773 "Percentage of processor time spent in kernel mode.");
2774 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
2775 "Percentage of processor time spent idling.");
2776 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
2777 "Average of current frequency of all processors.");
2778 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
2779 "Total physical memory installed.");
2780 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
2781 "Physical memory currently occupied.");
2782 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
2783 "Physical memory currently available to applications.");
2784 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
2785 "Total physical memory used by the hypervisor.");
2786 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
2787 "Total physical memory free inside the hypervisor.");
2788 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
2789 "Total physical memory ballooned by the hypervisor.");
2790 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
2791 "Total physical memory shared between VMs.");
2792
2793
2794 /* Create and register base metrics */
2795 IUnknown *objptr;
2796 ComObjPtr<Host> tmp = this;
2797 tmp.queryInterfaceTo(&objptr);
2798 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, objptr, cpuLoadUser, cpuLoadKernel,
2799 cpuLoadIdle);
2800 aCollector->registerBaseMetric (cpuLoad);
2801 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, objptr, cpuMhzSM);
2802 aCollector->registerBaseMetric (cpuMhz);
2803 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, objptr,
2804 ramUsageTotal,
2805 ramUsageUsed,
2806 ramUsageFree);
2807 aCollector->registerBaseMetric (ramUsage);
2808 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), objptr,
2809 ramVMMUsed,
2810 ramVMMFree,
2811 ramVMMBallooned,
2812 ramVMMShared);
2813 aCollector->registerBaseMetric (ramVmm);
2814
2815 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
2816 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2817 new pm::AggregateAvg()));
2818 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2819 new pm::AggregateMin()));
2820 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
2821 new pm::AggregateMax()));
2822
2823 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
2824 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2825 new pm::AggregateAvg()));
2826 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2827 new pm::AggregateMin()));
2828 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
2829 new pm::AggregateMax()));
2830
2831 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
2832 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2833 new pm::AggregateAvg()));
2834 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2835 new pm::AggregateMin()));
2836 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
2837 new pm::AggregateMax()));
2838
2839 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
2840 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2841 new pm::AggregateAvg()));
2842 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2843 new pm::AggregateMin()));
2844 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
2845 new pm::AggregateMax()));
2846
2847 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
2848 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2849 new pm::AggregateAvg()));
2850 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2851 new pm::AggregateMin()));
2852 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
2853 new pm::AggregateMax()));
2854
2855 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
2856 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2857 new pm::AggregateAvg()));
2858 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2859 new pm::AggregateMin()));
2860 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
2861 new pm::AggregateMax()));
2862
2863 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
2864 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2865 new pm::AggregateAvg()));
2866 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2867 new pm::AggregateMin()));
2868 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
2869 new pm::AggregateMax()));
2870
2871 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
2872 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2873 new pm::AggregateAvg()));
2874 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2875 new pm::AggregateMin()));
2876 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
2877 new pm::AggregateMax()));
2878
2879 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
2880 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2881 new pm::AggregateAvg()));
2882 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2883 new pm::AggregateMin()));
2884 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
2885 new pm::AggregateMax()));
2886
2887 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
2888 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2889 new pm::AggregateAvg()));
2890 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2891 new pm::AggregateMin()));
2892 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
2893 new pm::AggregateMax()));
2894
2895 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
2896 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2897 new pm::AggregateAvg()));
2898 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2899 new pm::AggregateMin()));
2900 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
2901 new pm::AggregateMax()));
2902}
2903
2904void Host::unregisterMetrics (PerformanceCollector *aCollector)
2905{
2906 aCollector->unregisterMetricsFor(this);
2907 aCollector->unregisterBaseMetricsFor(this);
2908}
2909
2910
2911/* static */
2912void Host::generateMACAddress(Utf8Str &mac)
2913{
2914 /*
2915 * Our strategy is as follows: the first three bytes are our fixed
2916 * vendor ID (080027). The remaining 3 bytes will be taken from the
2917 * start of a GUID. This is a fairly safe algorithm.
2918 */
2919 Guid guid;
2920 guid.create();
2921 mac = Utf8StrFmt("080027%02X%02X%02X",
2922 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
2923}
2924
2925#endif /* VBOX_WITH_RESOURCE_USAGE_API */
2926
2927/* 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