VirtualBox

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

Last change on this file since 86714 was 86331, checked in by vboxsync, 4 years ago

Main: bugref:9224: Changed the way to enumerate disks by scanning NT\GLOBAL?? in windows.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 147.6 KB
Line 
1/* $Id: HostImpl.cpp 86331 2020-09-28 17:21:43Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2004-2020 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 LOG_GROUP LOG_GROUP_MAIN_HOST
19
20#define __STDC_LIMIT_MACROS
21#define __STDC_CONSTANT_MACROS
22
23// VBoxNetCfg-win.h needs winsock2.h and thus MUST be included before any other
24// header file includes Windows.h.
25#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
26# include <VBox/VBoxNetCfg-win.h>
27#endif
28
29// for some reason Windows burns in sdk\...\winsock.h if this isn't included first
30#include "VBox/com/ptr.h"
31
32#include "HostImpl.h"
33
34#ifdef VBOX_WITH_USB
35# include "HostUSBDeviceImpl.h"
36# include "USBDeviceFilterImpl.h"
37# include "USBProxyService.h"
38#else
39# include "VirtualBoxImpl.h"
40#endif // VBOX_WITH_USB
41
42#include "HostNetworkInterfaceImpl.h"
43#include "HostVideoInputDeviceImpl.h"
44#include "MachineImpl.h"
45#include "AutoCaller.h"
46#include "LoggingNew.h"
47#include "Performance.h"
48#include "HostUpdateImpl.h"
49
50#include "MediumImpl.h"
51#include "HostPower.h"
52
53#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
54# include <HostHardwareLinux.h>
55#endif
56
57#include <set>
58
59#ifdef VBOX_WITH_RESOURCE_USAGE_API
60# include "PerformanceImpl.h"
61#endif /* VBOX_WITH_RESOURCE_USAGE_API */
62
63#if defined(RT_OS_DARWIN) && ARCH_BITS == 32
64# include <sys/types.h>
65# include <sys/sysctl.h>
66#endif
67
68#ifdef RT_OS_LINUX
69# include <sys/ioctl.h>
70# include <errno.h>
71# include <net/if.h>
72# include <net/if_arp.h>
73#endif /* RT_OS_LINUX */
74
75#ifdef RT_OS_SOLARIS
76# include <fcntl.h>
77# include <unistd.h>
78# include <stropts.h>
79# include <errno.h>
80# include <limits.h>
81# include <stdio.h>
82# include <libdevinfo.h>
83# include <sys/mkdev.h>
84# include <sys/scsi/generic/inquiry.h>
85# include <net/if.h>
86# include <sys/socket.h>
87# include <sys/sockio.h>
88# include <net/if_arp.h>
89# include <net/if.h>
90# include <sys/types.h>
91# include <sys/stat.h>
92# include <sys/cdio.h>
93# include <sys/dkio.h>
94# include <sys/mnttab.h>
95# include <sys/mntent.h>
96/* Dynamic loading of libhal on Solaris hosts */
97# ifdef VBOX_USE_LIBHAL
98# include "vbox-libhal.h"
99extern "C" char *getfullrawname(char *);
100# endif
101# include "solaris/DynLoadLibSolaris.h"
102
103/**
104 * Solaris DVD drive list as returned by getDVDInfoFromDevTree().
105 */
106typedef struct SOLARISDVD
107{
108 struct SOLARISDVD *pNext;
109 char szDescription[512];
110 char szRawDiskPath[PATH_MAX];
111} SOLARISDVD;
112/** Pointer to a Solaris DVD descriptor. */
113typedef SOLARISDVD *PSOLARISDVD;
114
115/** Solaris fixed drive (SSD, HDD, ++) descriptor list entry as returned by the
116 * solarisWalkDeviceNodeForFixedDrive callback. */
117typedef SOLARISDVD SOLARISFIXEDDISK;
118/** Pointer to a Solaris fixed drive (SSD, HDD, ++) descriptor. */
119typedef SOLARISFIXEDDISK *PSOLARISFIXEDDISK;
120
121
122#endif /* RT_OS_SOLARIS */
123
124#ifdef RT_OS_WINDOWS
125# define _WIN32_DCOM
126# include <iprt/win/windows.h>
127# include <shellapi.h>
128# define INITGUID
129# include <guiddef.h>
130# include <devguid.h>
131# include <iprt/win/objbase.h>
132# include <iprt/win/shlobj.h>
133# include <cfgmgr32.h>
134# include <tchar.h>
135#endif /* RT_OS_WINDOWS */
136
137#ifdef RT_OS_DARWIN
138# include "darwin/iokit.h"
139#endif
140
141#include <iprt/asm-amd64-x86.h>
142#ifdef RT_OS_SOLARIS
143# include <iprt/ctype.h>
144#endif
145#if defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)
146# include <iprt/file.h>
147#endif
148#include <iprt/mp.h>
149#include <iprt/env.h>
150#include <iprt/mem.h>
151#include <iprt/param.h>
152#include <iprt/string.h>
153#include <iprt/system.h>
154#ifndef RT_OS_WINDOWS
155# include <iprt/path.h>
156#endif
157#include <iprt/time.h>
158#ifdef RT_OS_WINDOWS
159# include <iprt/dir.h>
160# include <iprt/vfs.h>
161#endif
162
163#ifdef VBOX_WITH_HOSTNETIF_API
164# include "netif.h"
165#endif
166
167#include <VBox/usb.h>
168#include <VBox/err.h>
169#include <VBox/settings.h>
170#include <VBox/sup.h>
171#include <iprt/x86.h>
172
173#include "VBox/com/MultiResult.h"
174#include "VBox/com/array.h"
175
176#include <stdio.h>
177
178#include <algorithm>
179#include <iprt/sanitized/string>
180#include <vector>
181
182#include "HostDnsService.h"
183#include "HostDriveImpl.h"
184#include "HostDrivePartitionImpl.h"
185
186////////////////////////////////////////////////////////////////////////////////
187//
188// Host private data definition
189//
190////////////////////////////////////////////////////////////////////////////////
191
192struct Host::Data
193{
194 Data()
195 :
196 fDVDDrivesListBuilt(false),
197 fFloppyDrivesListBuilt(false),
198 fPersistentConfigUpToDate(false)
199 {};
200
201 VirtualBox *pParent;
202
203 HostNetworkInterfaceList llNetIfs; // list of network interfaces
204
205#ifdef VBOX_WITH_USB
206 USBDeviceFilterList llChildren; // all USB device filters
207 USBDeviceFilterList llUSBDeviceFilters; // USB device filters in use by the USB proxy service
208
209 /** Pointer to the USBProxyService object. */
210 USBProxyService *pUSBProxyService;
211#endif /* VBOX_WITH_USB */
212
213 // list of host drives; lazily created by getDVDDrives() and getFloppyDrives(),
214 // and protected by the medium tree lock handle (including the bools).
215 MediaList llDVDDrives,
216 llFloppyDrives;
217 bool fDVDDrivesListBuilt,
218 fFloppyDrivesListBuilt;
219
220#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
221 /** Object with information about host drives */
222 VBoxMainDriveInfo hostDrives;
223#endif
224
225 /** @name Features that can be queried with GetProcessorFeature.
226 * @{ */
227 bool fVTSupported,
228 fLongModeSupported,
229 fPAESupported,
230 fNestedPagingSupported,
231 fUnrestrictedGuestSupported,
232 fNestedHWVirtSupported,
233 fVirtVmsaveVmload,
234 fRecheckVTSupported;
235
236 /** @} */
237
238 /** 3D hardware acceleration supported? Tristate, -1 meaning not probed. */
239 int f3DAccelerationSupported;
240
241 HostPowerService *pHostPowerService;
242 /** Host's DNS informaton fetching */
243 HostDnsMonitorProxy hostDnsMonitorProxy;
244
245 /** Startup syncing of persistent config in extra data */
246 bool fPersistentConfigUpToDate;
247
248 /** The reference to the update check handler singleton. */
249 const ComObjPtr<HostUpdate> pHostUpdate;
250};
251
252
253////////////////////////////////////////////////////////////////////////////////
254//
255// Constructor / destructor
256//
257////////////////////////////////////////////////////////////////////////////////
258DEFINE_EMPTY_CTOR_DTOR(Host)
259
260HRESULT Host::FinalConstruct()
261{
262 return BaseFinalConstruct();
263}
264
265void Host::FinalRelease()
266{
267 uninit();
268 BaseFinalRelease();
269}
270
271/**
272 * Initializes the host object.
273 *
274 * @param aParent VirtualBox parent object.
275 */
276HRESULT Host::init(VirtualBox *aParent)
277{
278 HRESULT hrc;
279 LogFlowThisFunc(("aParent=%p\n", aParent));
280
281 /* Enclose the state transition NotReady->InInit->Ready */
282 AutoInitSpan autoInitSpan(this);
283 AssertReturn(autoInitSpan.isOk(), E_FAIL);
284
285 m = new Data();
286
287 m->pParent = aParent;
288
289#ifdef VBOX_WITH_USB
290 /*
291 * Create and initialize the USB Proxy Service.
292 */
293 m->pUSBProxyService = new USBProxyService(this);
294 hrc = m->pUSBProxyService->init();
295 AssertComRCReturn(hrc, hrc);
296#endif /* VBOX_WITH_USB */
297
298#ifdef VBOX_WITH_RESOURCE_USAGE_API
299 i_registerMetrics(aParent->i_performanceCollector());
300#endif /* VBOX_WITH_RESOURCE_USAGE_API */
301 /* Create the list of network interfaces so their metrics get registered. */
302 i_updateNetIfList();
303
304 m->hostDnsMonitorProxy.init(m->pParent);
305
306 hrc = unconst(m->pHostUpdate).createObject();
307 if (SUCCEEDED(hrc))
308 hrc = m->pHostUpdate->init(m->pParent);
309 AssertComRCReturn(hrc, hrc);
310
311#if defined(RT_OS_WINDOWS)
312 m->pHostPowerService = new HostPowerServiceWin(m->pParent);
313#elif defined(RT_OS_LINUX) && defined(VBOX_WITH_DBUS)
314 m->pHostPowerService = new HostPowerServiceLinux(m->pParent);
315#elif defined(RT_OS_DARWIN)
316 m->pHostPowerService = new HostPowerServiceDarwin(m->pParent);
317#else
318 m->pHostPowerService = new HostPowerService(m->pParent);
319#endif
320
321 /* Cache the features reported by GetProcessorFeature. */
322 m->fVTSupported = false;
323 m->fLongModeSupported = false;
324 m->fPAESupported = false;
325 m->fNestedPagingSupported = false;
326 m->fUnrestrictedGuestSupported = false;
327 m->fNestedHWVirtSupported = false;
328 m->fVirtVmsaveVmload = false;
329 m->fRecheckVTSupported = false;
330
331 if (ASMHasCpuId())
332 {
333 /* Note! This code is duplicated in SUPDrv.c and other places! */
334 uint32_t uMaxId, uVendorEBX, uVendorECX, uVendorEDX;
335 ASMCpuId(0, &uMaxId, &uVendorEBX, &uVendorECX, &uVendorEDX);
336 if (ASMIsValidStdRange(uMaxId))
337 {
338 /* PAE? */
339 uint32_t uDummy, fFeaturesEcx, fFeaturesEdx;
340 ASMCpuId(1, &uDummy, &uDummy, &fFeaturesEcx, &fFeaturesEdx);
341 m->fPAESupported = RT_BOOL(fFeaturesEdx & X86_CPUID_FEATURE_EDX_PAE);
342
343 /* Long Mode? */
344 uint32_t uExtMaxId, fExtFeaturesEcx, fExtFeaturesEdx;
345 ASMCpuId(0x80000000, &uExtMaxId, &uDummy, &uDummy, &uDummy);
346 ASMCpuId(0x80000001, &uDummy, &uDummy, &fExtFeaturesEcx, &fExtFeaturesEdx);
347 m->fLongModeSupported = ASMIsValidExtRange(uExtMaxId)
348 && (fExtFeaturesEdx & X86_CPUID_EXT_FEATURE_EDX_LONG_MODE);
349
350#if defined(RT_OS_DARWIN) && ARCH_BITS == 32 /* darwin.x86 has some optimizations of 64-bit on 32-bit. */
351 int f64bitCapable = 0;
352 size_t cbParameter = sizeof(f64bitCapable);
353 if (sysctlbyname("hw.cpu64bit_capable", &f64bitCapable, &cbParameter, NULL, NULL) != -1)
354 m->fLongModeSupported = f64bitCapable != 0;
355#endif
356
357 /* VT-x? */
358 if ( ASMIsIntelCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
359 || ASMIsViaCentaurCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
360 || ASMIsShanghaiCpuEx(uVendorEBX, uVendorECX, uVendorEDX))
361 {
362 if ( (fFeaturesEcx & X86_CPUID_FEATURE_ECX_VMX)
363 && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_MSR)
364 && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_FXSR)
365 )
366 {
367 const char *pszIgn;
368 int rc = SUPR3QueryVTxSupported(&pszIgn);
369 if (RT_SUCCESS(rc))
370 m->fVTSupported = true;
371 }
372 }
373 /* AMD-V */
374 else if ( ASMIsAmdCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
375 || ASMIsHygonCpuEx(uVendorEBX, uVendorECX, uVendorEDX))
376 {
377 if ( (fExtFeaturesEcx & X86_CPUID_AMD_FEATURE_ECX_SVM)
378 && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_MSR)
379 && (fFeaturesEdx & X86_CPUID_FEATURE_EDX_FXSR)
380 && ASMIsValidExtRange(uExtMaxId)
381 )
382 {
383 m->fVTSupported = true;
384 m->fUnrestrictedGuestSupported = true;
385
386 /* Query AMD features. */
387 if (uExtMaxId >= 0x8000000a)
388 {
389 uint32_t fSVMFeaturesEdx;
390 ASMCpuId(0x8000000a, &uDummy, &uDummy, &uDummy, &fSVMFeaturesEdx);
391 if (fSVMFeaturesEdx & X86_CPUID_SVM_FEATURE_EDX_NESTED_PAGING)
392 m->fNestedPagingSupported = true;
393 if (fSVMFeaturesEdx & X86_CPUID_SVM_FEATURE_EDX_VIRT_VMSAVE_VMLOAD)
394 m->fVirtVmsaveVmload = true;
395 }
396 }
397 }
398 }
399 }
400
401 /* Check with SUPDrv if VT-x and AMD-V are really supported (may fail). */
402 if (m->fVTSupported)
403 {
404 m->fRecheckVTSupported = true; /* Try again later when the driver is loaded; cleared by i_updateProcessorFeatures on success. */
405 i_updateProcessorFeatures();
406 }
407
408 /* Check for NEM in root paritition (hyper-V / windows). */
409 if (!m->fVTSupported && SUPR3IsNemSupportedWhenNoVtxOrAmdV())
410 {
411 m->fVTSupported = m->fNestedPagingSupported = true;
412 m->fRecheckVTSupported = false;
413 }
414
415#ifdef VBOX_WITH_3D_ACCELERATION
416 /* Test for 3D hardware acceleration support later when (if ever) need. */
417 m->f3DAccelerationSupported = -1;
418#else
419 m->f3DAccelerationSupported = false;
420#endif
421
422#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
423 /* Extract the list of configured host-only interfaces */
424 std::set<Utf8Str> aConfiguredNames;
425 SafeArray<BSTR> aGlobalExtraDataKeys;
426 hrc = aParent->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
427 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
428 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
429 {
430 Utf8Str strKey = aGlobalExtraDataKeys[i];
431
432 if (!strKey.startsWith("HostOnly/vboxnet"))
433 continue;
434
435 size_t pos = strKey.find("/", sizeof("HostOnly/vboxnet"));
436 if (pos != Utf8Str::npos)
437 aConfiguredNames.insert(strKey.substr(sizeof("HostOnly"),
438 pos - sizeof("HostOnly")));
439 }
440
441 for (std::set<Utf8Str>::const_iterator it = aConfiguredNames.begin();
442 it != aConfiguredNames.end();
443 ++it)
444 {
445 ComPtr<IHostNetworkInterface> hif;
446 ComPtr<IProgress> progress;
447
448 int vrc = NetIfCreateHostOnlyNetworkInterface(m->pParent,
449 hif.asOutParam(),
450 progress.asOutParam(),
451 it->c_str());
452 if (RT_FAILURE(vrc))
453 LogRel(("failed to create %s, error (%Rrc)\n", it->c_str(), vrc));
454 }
455
456#endif /* defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) */
457
458 /* Confirm a successful initialization */
459 autoInitSpan.setSucceeded();
460
461 return S_OK;
462}
463
464/**
465 * Uninitializes the host object and sets the ready flag to FALSE.
466 * Called either from FinalRelease() or by the parent when it gets destroyed.
467 */
468void Host::uninit()
469{
470 LogFlowThisFunc(("\n"));
471
472 /* Enclose the state transition Ready->InUninit->NotReady */
473 AutoUninitSpan autoUninitSpan(this);
474 if (autoUninitSpan.uninitDone())
475 return;
476
477#ifdef VBOX_WITH_RESOURCE_USAGE_API
478 PerformanceCollector *aCollector = m->pParent->i_performanceCollector();
479 i_unregisterMetrics(aCollector);
480#endif /* VBOX_WITH_RESOURCE_USAGE_API */
481 /*
482 * Note that unregisterMetrics() has unregistered all metrics associated
483 * with Host including network interface ones. We can destroy network
484 * interface objects now. Don't forget the uninit call, otherwise this
485 * causes a race with crashing API clients getting their stale references
486 * cleaned up and VirtualBox shutting down.
487 */
488 while (!m->llNetIfs.empty())
489 {
490 ComObjPtr<HostNetworkInterface> &pNet = m->llNetIfs.front();
491 pNet->uninit();
492 m->llNetIfs.pop_front();
493 }
494
495 m->hostDnsMonitorProxy.uninit();
496
497 if (m->pHostUpdate)
498 {
499 m->pHostUpdate->uninit();
500 unconst(m->pHostUpdate).setNull();
501 }
502
503#ifdef VBOX_WITH_USB
504 /* wait for USB proxy service to terminate before we uninit all USB
505 * devices */
506 LogFlowThisFunc(("Stopping USB proxy service...\n"));
507 delete m->pUSBProxyService;
508 m->pUSBProxyService = NULL;
509 LogFlowThisFunc(("Done stopping USB proxy service.\n"));
510#endif
511
512 delete m->pHostPowerService;
513
514#ifdef VBOX_WITH_USB
515 /* uninit all USB device filters still referenced by clients
516 * Note! HostUSBDeviceFilter::uninit() will modify llChildren.
517 * This list should be already empty, but better be safe than sorry. */
518 while (!m->llChildren.empty())
519 {
520 ComObjPtr<HostUSBDeviceFilter> &pChild = m->llChildren.front();
521 pChild->uninit();
522 m->llChildren.pop_front();
523 }
524
525 /* No need to uninit these, as either Machine::uninit() or the above loop
526 * already covered them all. Subset of llChildren. */
527 m->llUSBDeviceFilters.clear();
528#endif
529
530 /* uninit all host DVD medium objects */
531 while (!m->llDVDDrives.empty())
532 {
533 ComObjPtr<Medium> &pMedium = m->llDVDDrives.front();
534 pMedium->uninit();
535 m->llDVDDrives.pop_front();
536 }
537 /* uninit all host floppy medium objects */
538 while (!m->llFloppyDrives.empty())
539 {
540 ComObjPtr<Medium> &pMedium = m->llFloppyDrives.front();
541 pMedium->uninit();
542 m->llFloppyDrives.pop_front();
543 }
544
545 delete m;
546 m = NULL;
547}
548
549////////////////////////////////////////////////////////////////////////////////
550//
551// IHost public methods
552//
553////////////////////////////////////////////////////////////////////////////////
554
555/**
556 * Returns a list of host DVD drives.
557 *
558 * @returns COM status code
559 * @param aDVDDrives address of result pointer
560 */
561
562HRESULT Host::getDVDDrives(std::vector<ComPtr<IMedium> > &aDVDDrives)
563{
564 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
565
566 MediaList *pList;
567 HRESULT rc = i_getDrives(DeviceType_DVD, true /* fRefresh */, pList, treeLock);
568 if (FAILED(rc))
569 return rc;
570
571 aDVDDrives.resize(pList->size());
572 size_t i = 0;
573 for (MediaList::const_iterator it = pList->begin(); it != pList->end(); ++it, ++i)
574 (*it).queryInterfaceTo(aDVDDrives[i].asOutParam());
575
576 return S_OK;
577}
578
579/**
580 * Returns a list of host floppy drives.
581 *
582 * @returns COM status code
583 * @param aFloppyDrives address of result pointer
584 */
585HRESULT Host::getFloppyDrives(std::vector<ComPtr<IMedium> > &aFloppyDrives)
586{
587 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
588
589 MediaList *pList;
590 HRESULT rc = i_getDrives(DeviceType_Floppy, true /* fRefresh */, pList, treeLock);
591 if (FAILED(rc))
592 return rc;
593
594 aFloppyDrives.resize(pList->size());
595 size_t i = 0;
596 for (MediaList::const_iterator it = pList->begin(); it != pList->end(); ++it, ++i)
597 (*it).queryInterfaceTo(aFloppyDrives[i].asOutParam());
598
599 return S_OK;
600}
601
602
603#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
604# define VBOX_APP_NAME L"VirtualBox"
605
606static int vboxNetWinAddComponent(std::list< ComObjPtr<HostNetworkInterface> > *pPist,
607 INetCfgComponent *pncc)
608{
609 LPWSTR lpszName;
610 GUID IfGuid;
611 HRESULT hr;
612 int rc = VERR_GENERAL_FAILURE;
613
614 hr = pncc->GetDisplayName(&lpszName);
615 Assert(hr == S_OK);
616 if (hr == S_OK)
617 {
618 Bstr name((CBSTR)lpszName);
619
620 hr = pncc->GetInstanceGuid(&IfGuid);
621 Assert(hr == S_OK);
622 if (hr == S_OK)
623 {
624 /* create a new object and add it to the list */
625 ComObjPtr<HostNetworkInterface> iface;
626 iface.createObject();
627 /* remove the curly bracket at the end */
628 if (SUCCEEDED(iface->init(name, name, Guid(IfGuid), HostNetworkInterfaceType_Bridged)))
629 {
630// iface->setVirtualBox(m->pParent);
631 pPist->push_back(iface);
632 rc = VINF_SUCCESS;
633 }
634 else
635 {
636 Assert(0);
637 }
638 }
639 CoTaskMemFree(lpszName);
640 }
641
642 return rc;
643}
644#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
645
646#if defined(RT_OS_WINDOWS)
647struct HostOnlyInfo
648{
649 HostOnlyInfo() : fDhcpEnabled(false), uIPv6PrefixLength(0) {};
650
651 Bstr bstrName;
652 bool fDhcpEnabled;
653 Bstr strIPv4Address;
654 Bstr strIPv4NetMask;
655 Bstr strIPv6Address;
656 ULONG uIPv6PrefixLength;
657};
658
659typedef std::map<Utf8Str, HostOnlyInfo*> GUID_TO_HOST_ONLY_INFO;
660
661HRESULT Host::i_updatePersistentConfigForHostOnlyAdapters(void)
662{
663 /* No need to do the sync twice */
664 if (m->fPersistentConfigUpToDate)
665 return S_OK;
666 m->fPersistentConfigUpToDate = true;
667 bool fChangesMade = false;
668
669 /* Extract the list of configured host-only interfaces */
670 GUID_TO_HOST_ONLY_INFO aSavedAdapters;
671 SafeArray<BSTR> aGlobalExtraDataKeys;
672 HRESULT hrc = m->pParent->GetExtraDataKeys(ComSafeArrayAsOutParam(aGlobalExtraDataKeys));
673 AssertMsg(SUCCEEDED(hrc), ("VirtualBox::GetExtraDataKeys failed with %Rhrc\n", hrc));
674 for (size_t i = 0; i < aGlobalExtraDataKeys.size(); ++i)
675 {
676 Utf8Str strKey = aGlobalExtraDataKeys[i];
677
678 if (strKey.startsWith("HostOnly/{"))
679 {
680 Bstr bstrValue;
681 hrc = m->pParent->GetExtraData(aGlobalExtraDataKeys[i], bstrValue.asOutParam());
682 if (hrc != S_OK)
683 continue;
684
685 Utf8Str strGuid = strKey.substr(10, 36); /* Skip "HostOnly/{" */
686 if (aSavedAdapters.find(strGuid) == aSavedAdapters.end())
687 aSavedAdapters[strGuid] = new HostOnlyInfo();
688
689 if (strKey.endsWith("}/Name"))
690 aSavedAdapters[strGuid]->bstrName = bstrValue;
691 else if (strKey.endsWith("}/IPAddress"))
692 {
693 if (bstrValue == "DHCP")
694 aSavedAdapters[strGuid]->fDhcpEnabled = true;
695 else
696 aSavedAdapters[strGuid]->strIPv4Address = bstrValue;
697 }
698 else if (strKey.endsWith("}/IPNetMask"))
699 aSavedAdapters[strGuid]->strIPv4NetMask = bstrValue;
700 else if (strKey.endsWith("}/IPV6Address"))
701 aSavedAdapters[strGuid]->strIPv6Address = bstrValue;
702 else if (strKey.endsWith("}/IPV6PrefixLen"))
703 aSavedAdapters[strGuid]->uIPv6PrefixLength = Utf8Str(bstrValue).toUInt32();
704 }
705 }
706
707 /* Go over the list of existing adapters and update configs saved in extra data */
708 std::set<Bstr> aKnownNames;
709 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
710 {
711 /* Get type */
712 HostNetworkInterfaceType_T t;
713 hrc = (*it)->COMGETTER(InterfaceType)(&t);
714 if (FAILED(hrc) || t != HostNetworkInterfaceType_HostOnly)
715 continue;
716 /* Get id */
717 Bstr bstrGuid;
718 hrc = (*it)->COMGETTER(Id)(bstrGuid.asOutParam());
719 if (FAILED(hrc))
720 continue;
721 /* Get name */
722 Bstr bstrName;
723 hrc = (*it)->COMGETTER(Name)(bstrName.asOutParam());
724 if (FAILED(hrc))
725 continue;
726
727 /* Remove adapter from map as it does not need any further processing */
728 aSavedAdapters.erase(Utf8Str(bstrGuid));
729 /* Add adapter name to the list of known names, so we won't attempt to create adapters with the same name */
730 aKnownNames.insert(bstrName);
731 /* Make sure our extra data contains the latest config */
732 hrc = (*it)->i_updatePersistentConfig();
733 if (hrc != S_OK)
734 break;
735 }
736
737 /* The following loop not only creates missing adapters, it destroys HostOnlyInfo objects contained in the map as well */
738 for (GUID_TO_HOST_ONLY_INFO::iterator it = aSavedAdapters.begin(); it != aSavedAdapters.end(); ++it)
739 {
740 Utf8Str strGuid = (*it).first;
741 HostOnlyInfo *pInfo = (*it).second;
742 /* We create adapters only if we haven't seen one with the same name */
743 if (aKnownNames.find(pInfo->bstrName) == aKnownNames.end())
744 {
745 /* There is no adapter with such name yet, create it */
746 ComPtr<IHostNetworkInterface> hif;
747 ComPtr<IProgress> progress;
748
749 int vrc = NetIfCreateHostOnlyNetworkInterface(m->pParent, hif.asOutParam(), progress.asOutParam(),
750 pInfo->bstrName.raw());
751 if (RT_FAILURE(vrc))
752 {
753 LogRel(("Failed to create host-only adapter (%Rrc)\n", vrc));
754 hrc = E_UNEXPECTED;
755 break;
756 }
757
758 /* Wait for the adapter to get configured completely, before we modify IP addresses. */
759 progress->WaitForCompletion(-1);
760 fChangesMade = true;
761 if (pInfo->fDhcpEnabled)
762 {
763 hrc = hif->EnableDynamicIPConfig();
764 if (FAILED(hrc))
765 LogRel(("EnableDynamicIPConfig failed with 0x%x\n", hrc));
766 }
767 else
768 {
769 hrc = hif->EnableStaticIPConfig(pInfo->strIPv4Address.raw(), pInfo->strIPv4NetMask.raw());
770 if (FAILED(hrc))
771 LogRel(("EnableStaticIpConfig failed with 0x%x\n", hrc));
772 }
773# if 0
774 /* Somehow HostNetworkInterface::EnableStaticIPConfigV6 is not implemented yet. */
775 if (SUCCEEDED(hrc))
776 {
777 hrc = hif->EnableStaticIPConfigV6(pInfo->strIPv6Address.raw(), pInfo->uIPv6PrefixLength);
778 if (FAILED(hrc))
779 LogRel(("EnableStaticIPConfigV6 failed with 0x%x\n", hrc));
780 }
781# endif
782 /* Now we have seen this name */
783 aKnownNames.insert(pInfo->bstrName);
784 /* Drop the old config as the newly created adapter has different GUID */
785 i_removePersistentConfig(strGuid);
786 }
787 delete pInfo;
788 }
789 /* Update the list again if we have created some adapters */
790 if (SUCCEEDED(hrc) && fChangesMade)
791 hrc = i_updateNetIfList();
792
793 return hrc;
794}
795#endif /* defined(RT_OS_WINDOWS) */
796
797/**
798 * Returns a list of host network interfaces.
799 *
800 * @returns COM status code
801 * @param aNetworkInterfaces address of result pointer
802 */
803HRESULT Host::getNetworkInterfaces(std::vector<ComPtr<IHostNetworkInterface> > &aNetworkInterfaces)
804{
805#if defined(RT_OS_WINDOWS) || defined(VBOX_WITH_NETFLT) /*|| defined(RT_OS_OS2)*/
806# ifdef VBOX_WITH_HOSTNETIF_API
807 HRESULT rc = i_updateNetIfList();
808 if (FAILED(rc))
809 {
810 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
811 return rc;
812 }
813#if defined(RT_OS_WINDOWS)
814 rc = i_updatePersistentConfigForHostOnlyAdapters();
815 if (FAILED(rc))
816 {
817 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
818 return rc;
819 }
820#endif /* defined(RT_OS_WINDOWS) */
821
822 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
823
824 aNetworkInterfaces.resize(m->llNetIfs.size());
825 size_t i = 0;
826 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it, ++i)
827 (*it).queryInterfaceTo(aNetworkInterfaces[i].asOutParam());
828
829 return S_OK;
830# else
831 std::list<ComObjPtr<HostNetworkInterface> > list;
832
833# if defined(RT_OS_DARWIN)
834 PDARWINETHERNIC pEtherNICs = DarwinGetEthernetControllers();
835 while (pEtherNICs)
836 {
837 ComObjPtr<HostNetworkInterface> IfObj;
838 IfObj.createObject();
839 if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
840 list.push_back(IfObj);
841
842 /* next, free current */
843 void *pvFree = pEtherNICs;
844 pEtherNICs = pEtherNICs->pNext;
845 RTMemFree(pvFree);
846 }
847
848# elif defined RT_OS_WINDOWS
849# ifndef VBOX_WITH_NETFLT
850 hr = E_NOTIMPL;
851# else /* # if defined VBOX_WITH_NETFLT */
852 INetCfg *pNc;
853 INetCfgComponent *pMpNcc;
854 INetCfgComponent *pTcpIpNcc;
855 LPWSTR lpszApp;
856 HRESULT hr;
857 IEnumNetCfgBindingPath *pEnumBp;
858 INetCfgBindingPath *pBp;
859 IEnumNetCfgBindingInterface *pEnumBi;
860 INetCfgBindingInterface *pBi;
861
862 /* we are using the INetCfg API for getting the list of miniports */
863 hr = VBoxNetCfgWinQueryINetCfg(FALSE,
864 VBOX_APP_NAME,
865 &pNc,
866 &lpszApp);
867 Assert(hr == S_OK);
868 if (hr == S_OK)
869 {
870# ifdef VBOX_NETFLT_ONDEMAND_BIND
871 /* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
872 hr = pNc->FindComponent(L"MS_TCPIP", &pTcpIpNcc);
873# else
874 /* for the filter-based approach we get all miniports our filter (oracle_VBoxNetLwf)is bound to */
875 hr = pNc->FindComponent(L"oracle_VBoxNetLwf", &pTcpIpNcc);
876 if (hr != S_OK)
877 {
878 /* fall back to NDIS5 miniport lookup (sun_VBoxNetFlt) */
879 hr = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
880 }
881# ifndef VBOX_WITH_HARDENING
882 if (hr != S_OK)
883 {
884 /** @todo try to install the netflt from here */
885 }
886# endif
887
888# endif
889
890 if (hr == S_OK)
891 {
892 hr = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
893 Assert(hr == S_OK);
894 if (hr == S_OK)
895 {
896 hr = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
897 Assert(hr == S_OK || hr == S_FALSE);
898 while (hr == S_OK)
899 {
900 /* S_OK == enabled, S_FALSE == disabled */
901 if (pBp->IsEnabled() == S_OK)
902 {
903 hr = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
904 Assert(hr == S_OK);
905 if (hr == S_OK)
906 {
907 hr = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
908 Assert(hr == S_OK);
909 while (hr == S_OK)
910 {
911 hr = pBi->GetLowerComponent(&pMpNcc);
912 Assert(hr == S_OK);
913 if (hr == S_OK)
914 {
915 ULONG uComponentStatus;
916 hr = pMpNcc->GetDeviceStatus(&uComponentStatus);
917 Assert(hr == S_OK);
918 if (hr == S_OK)
919 {
920 if (uComponentStatus == 0)
921 {
922 vboxNetWinAddComponent(&list, pMpNcc);
923 }
924 }
925 VBoxNetCfgWinReleaseRef(pMpNcc);
926 }
927 VBoxNetCfgWinReleaseRef(pBi);
928
929 hr = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
930 }
931 VBoxNetCfgWinReleaseRef(pEnumBi);
932 }
933 }
934 VBoxNetCfgWinReleaseRef(pBp);
935
936 hr = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
937 }
938 VBoxNetCfgWinReleaseRef(pEnumBp);
939 }
940 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
941 }
942 else
943 {
944 LogRel(("failed to get the oracle_VBoxNetLwf(sun_VBoxNetFlt) component, error (0x%x)\n", hr));
945 }
946
947 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
948 }
949# endif /* # if defined VBOX_WITH_NETFLT */
950
951
952# elif defined RT_OS_LINUX
953 int sock = socket(AF_INET, SOCK_DGRAM, 0);
954 if (sock >= 0)
955 {
956 char pBuffer[2048];
957 struct ifconf ifConf;
958 ifConf.ifc_len = sizeof(pBuffer);
959 ifConf.ifc_buf = pBuffer;
960 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
961 {
962 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
963 {
964 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
965 {
966 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
967 {
968 RTUUID uuid;
969 Assert(sizeof(uuid) <= sizeof(*pReq));
970 memcpy(&uuid, pReq, sizeof(uuid));
971
972 ComObjPtr<HostNetworkInterface> IfObj;
973 IfObj.createObject();
974 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
975 list.push_back(IfObj);
976 }
977 }
978 }
979 }
980 close(sock);
981 }
982# endif /* RT_OS_LINUX */
983
984 aNetworkInterfaces.resize(list.size());
985 size_t i = 0;
986 for (std::list<ComObjPtr<HostNetworkInterface> >::const_iterator it = list.begin(); it != list.end(); ++it, ++i)
987 aNetworkInterfaces[i] = *it;
988
989 return S_OK;
990# endif
991#else
992 /* Not implemented / supported on this platform. */
993 RT_NOREF(aNetworkInterfaces);
994 ReturnComNotImplemented();
995#endif
996}
997
998HRESULT Host::getUSBDevices(std::vector<ComPtr<IHostUSBDevice> > &aUSBDevices)
999{
1000#ifdef VBOX_WITH_USB
1001 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1002
1003 MultiResult rc = i_checkUSBProxyService();
1004 if (FAILED(rc))
1005 return rc;
1006
1007 return m->pUSBProxyService->getDeviceCollection(aUSBDevices);
1008#else
1009 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1010 * extended error info to indicate that USB is simply not available
1011 * (w/o treating it as a failure), for example, as in OSE. */
1012 RT_NOREF(aUSBDevices);
1013 ReturnComNotImplemented();
1014#endif
1015}
1016
1017/**
1018 * This method return the list of registered name servers
1019 */
1020HRESULT Host::getNameServers(std::vector<com::Utf8Str> &aNameServers)
1021{
1022 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1023 return m->hostDnsMonitorProxy.GetNameServers(aNameServers);
1024}
1025
1026
1027/**
1028 * This method returns the domain name of the host
1029 */
1030HRESULT Host::getDomainName(com::Utf8Str &aDomainName)
1031{
1032 /* XXX: note here should be synchronization with thread polling state
1033 * changes in name resoving system on host */
1034 return m->hostDnsMonitorProxy.GetDomainName(&aDomainName);
1035}
1036
1037
1038/**
1039 * This method returns the search string.
1040 */
1041HRESULT Host::getSearchStrings(std::vector<com::Utf8Str> &aSearchStrings)
1042{
1043 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1044 return m->hostDnsMonitorProxy.GetSearchStrings(aSearchStrings);
1045}
1046
1047HRESULT Host::getUSBDeviceFilters(std::vector<ComPtr<IHostUSBDeviceFilter> > &aUSBDeviceFilters)
1048{
1049#ifdef VBOX_WITH_USB
1050 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1051
1052 MultiResult rc = i_checkUSBProxyService();
1053 if (FAILED(rc))
1054 return rc;
1055
1056 aUSBDeviceFilters.resize(m->llUSBDeviceFilters.size());
1057 size_t i = 0;
1058 for (USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin(); it != m->llUSBDeviceFilters.end(); ++it, ++i)
1059 (*it).queryInterfaceTo(aUSBDeviceFilters[i].asOutParam());
1060
1061 return rc;
1062#else
1063 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1064 * extended error info to indicate that USB is simply not available
1065 * (w/o treating it as a failure), for example, as in OSE. */
1066 RT_NOREF(aUSBDeviceFilters);
1067 ReturnComNotImplemented();
1068#endif
1069}
1070
1071/**
1072 * Returns the number of installed logical processors
1073 *
1074 * @returns COM status code
1075 * @param aCount address of result variable
1076 */
1077
1078HRESULT Host::getProcessorCount(ULONG *aCount)
1079{
1080 // no locking required
1081
1082 *aCount = RTMpGetPresentCount();
1083 return S_OK;
1084}
1085
1086/**
1087 * Returns the number of online logical processors
1088 *
1089 * @returns COM status code
1090 * @param aCount address of result variable
1091 */
1092HRESULT Host::getProcessorOnlineCount(ULONG *aCount)
1093{
1094 // no locking required
1095
1096 *aCount = RTMpGetOnlineCount();
1097 return S_OK;
1098}
1099
1100/**
1101 * Returns the number of installed physical processor cores.
1102 *
1103 * @returns COM status code
1104 * @param aCount address of result variable
1105 */
1106HRESULT Host::getProcessorCoreCount(ULONG *aCount)
1107{
1108 // no locking required
1109
1110 *aCount = RTMpGetPresentCoreCount();
1111 return S_OK;
1112}
1113
1114/**
1115 * Returns the number of installed physical processor cores.
1116 *
1117 * @returns COM status code
1118 * @param aCount address of result variable
1119 */
1120HRESULT Host::getProcessorOnlineCoreCount(ULONG *aCount)
1121{
1122 // no locking required
1123
1124 *aCount = RTMpGetOnlineCoreCount();
1125 return S_OK;
1126}
1127
1128/**
1129 * Returns the (approximate) maximum speed of the given host CPU in MHz
1130 *
1131 * @returns COM status code
1132 * @param aCpuId id to get info for.
1133 * @param aSpeed address of result variable, speed is 0 if unknown or aCpuId
1134 * is invalid.
1135 */
1136HRESULT Host::getProcessorSpeed(ULONG aCpuId,
1137 ULONG *aSpeed)
1138{
1139 // no locking required
1140
1141 *aSpeed = RTMpGetMaxFrequency(aCpuId);
1142 return S_OK;
1143}
1144
1145/**
1146 * Returns a description string for the host CPU
1147 *
1148 * @returns COM status code
1149 * @param aCpuId id to get info for.
1150 * @param aDescription address of result variable, empty string if not known
1151 * or aCpuId is invalid.
1152 */
1153HRESULT Host::getProcessorDescription(ULONG aCpuId, com::Utf8Str &aDescription)
1154{
1155 // no locking required
1156
1157 char szCPUModel[80];
1158 szCPUModel[0] = 0;
1159 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
1160 if (RT_FAILURE(vrc))
1161 return E_FAIL; /** @todo error reporting? */
1162
1163 aDescription = Utf8Str(szCPUModel);
1164
1165 return S_OK;
1166}
1167
1168/**
1169 * Updates fVTSupported, fNestedPagingSupported, fUnrestrictedGuestSupported,
1170 * fVirtVmsaveVmload and fNestedHWVirtSupported with info from SUPR3QueryVTCaps().
1171 *
1172 * This is repeated till we successfully open the support driver, in case it
1173 * is loaded after VBoxSVC starts.
1174 */
1175void Host::i_updateProcessorFeatures()
1176{
1177 /* Perhaps the driver is available now... */
1178 int rc = SUPR3InitEx(false /*fUnrestricted*/, NULL);
1179 if (RT_SUCCESS(rc))
1180 {
1181 uint32_t fVTCaps;
1182 rc = SUPR3QueryVTCaps(&fVTCaps);
1183 AssertRC(rc);
1184
1185 SUPR3Term(false);
1186
1187 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
1188 if (RT_FAILURE(rc))
1189 {
1190 LogRel(("SUPR0QueryVTCaps -> %Rrc\n", rc));
1191 fVTCaps = 0;
1192 }
1193 m->fVTSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VT_X)) != 0;
1194 m->fNestedPagingSupported = (fVTCaps & SUPVTCAPS_NESTED_PAGING) != 0;
1195 m->fUnrestrictedGuestSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VTX_UNRESTRICTED_GUEST)) != 0;
1196 m->fNestedHWVirtSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_NESTED_PAGING))
1197 == (SUPVTCAPS_AMD_V | SUPVTCAPS_NESTED_PAGING)
1198 || (fVTCaps & ( SUPVTCAPS_VT_X | SUPVTCAPS_NESTED_PAGING
1199 | SUPVTCAPS_VTX_UNRESTRICTED_GUEST | SUPVTCAPS_VTX_VMCS_SHADOWING))
1200 == ( SUPVTCAPS_VT_X | SUPVTCAPS_NESTED_PAGING
1201 | SUPVTCAPS_VTX_UNRESTRICTED_GUEST | SUPVTCAPS_VTX_VMCS_SHADOWING);
1202 m->fVirtVmsaveVmload = (fVTCaps & SUPVTCAPS_AMDV_VIRT_VMSAVE_VMLOAD) != 0;
1203 m->fRecheckVTSupported = false; /* No need to try again, we cached everything. */
1204 }
1205}
1206
1207/**
1208 * Returns whether a host processor feature is supported or not
1209 *
1210 * @returns COM status code
1211 * @param aFeature to query.
1212 * @param aSupported supported bool result variable
1213 */
1214HRESULT Host::getProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
1215{
1216 /* Validate input. */
1217 switch (aFeature)
1218 {
1219 case ProcessorFeature_HWVirtEx:
1220 case ProcessorFeature_PAE:
1221 case ProcessorFeature_LongMode:
1222 case ProcessorFeature_NestedPaging:
1223 case ProcessorFeature_UnrestrictedGuest:
1224 case ProcessorFeature_NestedHWVirt:
1225 case ProcessorFeature_VirtVmsaveVmload:
1226 break;
1227 default:
1228 return setError(E_INVALIDARG, tr("The aFeature value %d (%#x) is out of range."), (int)aFeature, (int)aFeature);
1229 }
1230
1231 /* Do the job. */
1232 AutoCaller autoCaller(this);
1233 HRESULT hrc = autoCaller.rc();
1234 if (SUCCEEDED(hrc))
1235 {
1236 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1237
1238 if ( m->fRecheckVTSupported
1239 && ( aFeature == ProcessorFeature_HWVirtEx
1240 || aFeature == ProcessorFeature_NestedPaging
1241 || aFeature == ProcessorFeature_UnrestrictedGuest
1242 || aFeature == ProcessorFeature_NestedHWVirt
1243 || aFeature == ProcessorFeature_VirtVmsaveVmload)
1244 )
1245 {
1246 alock.release();
1247 i_updateProcessorFeatures();
1248 alock.acquire();
1249 }
1250
1251 switch (aFeature)
1252 {
1253 case ProcessorFeature_HWVirtEx:
1254 *aSupported = m->fVTSupported;
1255 break;
1256
1257 case ProcessorFeature_PAE:
1258 *aSupported = m->fPAESupported;
1259 break;
1260
1261 case ProcessorFeature_LongMode:
1262 *aSupported = m->fLongModeSupported;
1263 break;
1264
1265 case ProcessorFeature_NestedPaging:
1266 *aSupported = m->fNestedPagingSupported;
1267 break;
1268
1269 case ProcessorFeature_UnrestrictedGuest:
1270 *aSupported = m->fUnrestrictedGuestSupported;
1271 break;
1272
1273 case ProcessorFeature_NestedHWVirt:
1274 *aSupported = m->fNestedHWVirtSupported;
1275 break;
1276
1277 case ProcessorFeature_VirtVmsaveVmload:
1278 *aSupported = m->fVirtVmsaveVmload;
1279 break;
1280
1281 default:
1282 AssertFailed();
1283 }
1284 }
1285 return hrc;
1286}
1287
1288/**
1289 * Returns the specific CPUID leaf.
1290 *
1291 * @returns COM status code
1292 * @param aCpuId The CPU number. Mostly ignored.
1293 * @param aLeaf The leaf number.
1294 * @param aSubLeaf The sub-leaf number.
1295 * @param aValEAX Where to return EAX.
1296 * @param aValEBX Where to return EBX.
1297 * @param aValECX Where to return ECX.
1298 * @param aValEDX Where to return EDX.
1299 */
1300HRESULT Host::getProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
1301 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
1302{
1303 // no locking required
1304
1305 /* Check that the CPU is online. */
1306 /** @todo later use RTMpOnSpecific. */
1307 if (!RTMpIsCpuOnline(aCpuId))
1308 return RTMpIsCpuPresent(aCpuId)
1309 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
1310 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
1311
1312 uint32_t uEAX, uEBX, uECX, uEDX;
1313 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
1314 *aValEAX = uEAX;
1315 *aValEBX = uEBX;
1316 *aValECX = uECX;
1317 *aValEDX = uEDX;
1318
1319 return S_OK;
1320}
1321
1322/**
1323 * Returns the amount of installed system memory in megabytes
1324 *
1325 * @returns COM status code
1326 * @param aSize address of result variable
1327 */
1328HRESULT Host::getMemorySize(ULONG *aSize)
1329{
1330 // no locking required
1331
1332 uint64_t cb;
1333 int rc = RTSystemQueryTotalRam(&cb);
1334 if (RT_FAILURE(rc))
1335 return E_FAIL;
1336 *aSize = (ULONG)(cb / _1M);
1337 return S_OK;
1338}
1339
1340/**
1341 * Returns the current system memory free space in megabytes
1342 *
1343 * @returns COM status code
1344 * @param aAvailable address of result variable
1345 */
1346HRESULT Host::getMemoryAvailable(ULONG *aAvailable)
1347{
1348 // no locking required
1349
1350 uint64_t cb;
1351 int rc = RTSystemQueryAvailableRam(&cb);
1352 if (RT_FAILURE(rc))
1353 return E_FAIL;
1354 *aAvailable = (ULONG)(cb / _1M);
1355 return S_OK;
1356}
1357
1358/**
1359 * Returns the name string of the host operating system
1360 *
1361 * @returns COM status code
1362 * @param aOperatingSystem result variable
1363 */
1364HRESULT Host::getOperatingSystem(com::Utf8Str &aOperatingSystem)
1365{
1366 // no locking required
1367
1368 char szOSName[80];
1369 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1370 if (RT_FAILURE(vrc))
1371 return E_FAIL; /** @todo error reporting? */
1372 aOperatingSystem = Utf8Str(szOSName);
1373 return S_OK;
1374}
1375
1376/**
1377 * Returns the version string of the host operating system
1378 *
1379 * @returns COM status code
1380 * @param aVersion address of result variable
1381 */
1382HRESULT Host::getOSVersion(com::Utf8Str &aVersion)
1383{
1384 // no locking required
1385
1386 /* Get the OS release. Reserve some buffer space for the service pack. */
1387 char szOSRelease[128];
1388 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1389 if (RT_FAILURE(vrc))
1390 return E_FAIL; /** @todo error reporting? */
1391
1392 /* Append the service pack if present. */
1393 char szOSServicePack[80];
1394 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1395 if (RT_FAILURE(vrc))
1396 {
1397 if (vrc != VERR_NOT_SUPPORTED)
1398 return E_FAIL; /** @todo error reporting? */
1399 szOSServicePack[0] = '\0';
1400 }
1401 if (szOSServicePack[0] != '\0')
1402 {
1403 char *psz = strchr(szOSRelease, '\0');
1404 RTStrPrintf(psz, (size_t)(&szOSRelease[sizeof(szOSRelease)] - psz), "sp%s", szOSServicePack);
1405 }
1406
1407 aVersion = szOSRelease;
1408 return S_OK;
1409}
1410
1411/**
1412 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1413 *
1414 * @returns COM status code
1415 * @param aUTCTime address of result variable
1416 */
1417HRESULT Host::getUTCTime(LONG64 *aUTCTime)
1418{
1419 // no locking required
1420
1421 RTTIMESPEC now;
1422 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1423
1424 return S_OK;
1425}
1426
1427
1428HRESULT Host::getAcceleration3DAvailable(BOOL *aSupported)
1429{
1430 HRESULT hrc = S_OK;
1431 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1432 if (m->f3DAccelerationSupported != -1)
1433 *aSupported = m->f3DAccelerationSupported;
1434 else
1435 {
1436 alock.release();
1437
1438#ifdef VBOX_WITH_3D_ACCELERATION
1439 bool fSupported = VBoxOglIs3DAccelerationSupported();
1440#else
1441 bool fSupported = false; /* shoudn't get here, but just in case. */
1442#endif
1443 AutoWriteLock alock2(this COMMA_LOCKVAL_SRC_POS);
1444
1445 m->f3DAccelerationSupported = fSupported;
1446 alock2.release();
1447 *aSupported = fSupported;
1448 }
1449
1450#ifdef DEBUG_misha
1451 AssertMsgFailed(("should not be here any more!\n"));
1452#endif
1453
1454 return hrc;
1455}
1456
1457HRESULT Host::createHostOnlyNetworkInterface(ComPtr<IHostNetworkInterface> &aHostInterface,
1458 ComPtr<IProgress> &aProgress)
1459
1460{
1461#ifdef VBOX_WITH_HOSTNETIF_API
1462 /* No need to lock anything. If there ever will - watch out, the function
1463 * called below grabs the VirtualBox lock. */
1464
1465 int vrc = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostInterface.asOutParam(), aProgress.asOutParam());
1466 if (RT_SUCCESS(vrc))
1467 {
1468 if (aHostInterface.isNull())
1469 return setError(E_FAIL,
1470 tr("Unable to create a host network interface"));
1471
1472# if !defined(RT_OS_WINDOWS)
1473 Bstr tmpAddr, tmpMask, tmpName;
1474 HRESULT hrc;
1475 hrc = aHostInterface->COMGETTER(Name)(tmpName.asOutParam());
1476 ComAssertComRCRet(hrc, hrc);
1477 hrc = aHostInterface->COMGETTER(IPAddress)(tmpAddr.asOutParam());
1478 ComAssertComRCRet(hrc, hrc);
1479 hrc = aHostInterface->COMGETTER(NetworkMask)(tmpMask.asOutParam());
1480 ComAssertComRCRet(hrc, hrc);
1481 /*
1482 * We need to write the default IP address and mask to extra data now,
1483 * so the interface gets re-created after vboxnetadp.ko reload.
1484 * Note that we avoid calling EnableStaticIpConfig since it would
1485 * change the address on host's interface as well and we want to
1486 * postpone the change until VM actually starts.
1487 */
1488 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
1489 tmpName.raw()).raw(),
1490 tmpAddr.raw());
1491 ComAssertComRCRet(hrc, hrc);
1492
1493 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
1494 tmpName.raw()).raw(),
1495 tmpMask.raw());
1496 ComAssertComRCRet(hrc, hrc);
1497# endif /* !defined(RT_OS_WINDOWS) */
1498 }
1499
1500 return S_OK;
1501#else
1502 return E_NOTIMPL;
1503#endif
1504}
1505
1506
1507#ifdef RT_OS_WINDOWS
1508HRESULT Host::i_removePersistentConfig(const Bstr &bstrGuid)
1509{
1510 HRESULT hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/Name", bstrGuid.raw()).raw(), NULL);
1511 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPAddress", bstrGuid.raw()).raw(), NULL);
1512 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPNetMask", bstrGuid.raw()).raw(), NULL);
1513 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPV6Address", bstrGuid.raw()).raw(), NULL);
1514 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPV6PrefixLen", bstrGuid.raw()).raw(), NULL);
1515 return hrc;
1516}
1517#endif /* RT_OS_WINDOWS */
1518
1519HRESULT Host::removeHostOnlyNetworkInterface(const com::Guid &aId,
1520 ComPtr<IProgress> &aProgress)
1521
1522{
1523#ifdef VBOX_WITH_HOSTNETIF_API
1524 /* No need to lock anything, the code below does not touch the state
1525 * of the host object. If that ever changes then check for lock order
1526 * violations with the called functions. */
1527
1528 Bstr name;
1529 HRESULT rc;
1530
1531 /* first check whether an interface with the given name already exists */
1532 {
1533 ComPtr<IHostNetworkInterface> iface;
1534 rc = findHostNetworkInterfaceById(aId, iface);
1535 if (FAILED(rc))
1536 return setError(VBOX_E_OBJECT_NOT_FOUND,
1537 tr("Host network interface with UUID {%RTuuid} does not exist"),
1538 Guid(aId).raw());
1539 rc = iface->COMGETTER(Name)(name.asOutParam());
1540 ComAssertComRCRet(rc, rc);
1541 }
1542
1543 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, aId, aProgress.asOutParam());
1544 if (RT_SUCCESS(r))
1545 {
1546 /* Drop configuration parameters for removed interface */
1547#ifdef RT_OS_WINDOWS
1548 rc = i_removePersistentConfig(Utf8StrFmt("%RTuuid", &aId));
1549 if (FAILED(rc))
1550 LogRel(("i_removePersistentConfig(%RTuuid) failed with 0x%x\n", &aId, rc));
1551#else /* !RT_OS_WINDOWS */
1552 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1553 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1554 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1555 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1556#endif /* !RT_OS_WINDOWS */
1557
1558 return S_OK;
1559 }
1560
1561 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1562#else
1563 return E_NOTIMPL;
1564#endif
1565}
1566
1567HRESULT Host::createUSBDeviceFilter(const com::Utf8Str &aName,
1568 ComPtr<IHostUSBDeviceFilter> &aFilter)
1569{
1570#ifdef VBOX_WITH_USB
1571
1572 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1573
1574 ComObjPtr<HostUSBDeviceFilter> filter;
1575 filter.createObject();
1576 HRESULT rc = filter->init(this, Bstr(aName).raw());
1577 ComAssertComRCRet(rc, rc);
1578 rc = filter.queryInterfaceTo(aFilter.asOutParam());
1579 AssertComRCReturn(rc, rc);
1580 return S_OK;
1581#else
1582 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1583 * extended error info to indicate that USB is simply not available
1584 * (w/o treating it as a failure), for example, as in OSE. */
1585 RT_NOREF(aName, aFilter);
1586 ReturnComNotImplemented();
1587#endif
1588}
1589
1590HRESULT Host::insertUSBDeviceFilter(ULONG aPosition,
1591 const ComPtr<IHostUSBDeviceFilter> &aFilter)
1592{
1593#ifdef VBOX_WITH_USB
1594 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1595
1596 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1597
1598 MultiResult rc = i_checkUSBProxyService();
1599 if (FAILED(rc))
1600 return rc;
1601
1602 ComObjPtr<HostUSBDeviceFilter> pFilter;
1603 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1604 it != m->llChildren.end();
1605 ++it)
1606 {
1607 if (*it == aFilter)
1608 {
1609 pFilter = *it;
1610 break;
1611 }
1612 }
1613 if (pFilter.isNull())
1614 return setError(VBOX_E_INVALID_OBJECT_STATE,
1615 tr("The given USB device filter is not created within this VirtualBox instance"));
1616
1617 if (pFilter->mInList)
1618 return setError(E_INVALIDARG,
1619 tr("The given USB device filter is already in the list"));
1620
1621 /* iterate to the position... */
1622 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1623 std::advance(itPos, aPosition);
1624 /* ...and insert */
1625 m->llUSBDeviceFilters.insert(itPos, pFilter);
1626 pFilter->mInList = true;
1627
1628 /* notify the proxy (only when the filter is active) */
1629 if ( m->pUSBProxyService->isActive()
1630 && pFilter->i_getData().mData.fActive)
1631 {
1632 ComAssertRet(pFilter->i_getId() == NULL, E_FAIL);
1633 pFilter->i_getId() = m->pUSBProxyService->insertFilter(&pFilter->i_getData().mUSBFilter);
1634 }
1635
1636 // save the global settings; for that we should hold only the VirtualBox lock
1637 alock.release();
1638 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1639 return rc = m->pParent->i_saveSettings();
1640#else
1641
1642 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1643 * extended error info to indicate that USB is simply not available
1644 * (w/o treating it as a failure), for example, as in OSE. */
1645 RT_NOREF(aPosition, aFilter);
1646 ReturnComNotImplemented();
1647#endif
1648}
1649
1650HRESULT Host::removeUSBDeviceFilter(ULONG aPosition)
1651{
1652#ifdef VBOX_WITH_USB
1653
1654 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1655 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1656
1657 MultiResult rc = i_checkUSBProxyService();
1658 if (FAILED(rc))
1659 return rc;
1660
1661 if (!m->llUSBDeviceFilters.size())
1662 return setError(E_INVALIDARG,
1663 tr("The USB device filter list is empty"));
1664
1665 if (aPosition >= m->llUSBDeviceFilters.size())
1666 return setError(E_INVALIDARG,
1667 tr("Invalid position: %lu (must be in range [0, %lu])"),
1668 aPosition, m->llUSBDeviceFilters.size() - 1);
1669
1670 ComObjPtr<HostUSBDeviceFilter> filter;
1671 {
1672 /* iterate to the position... */
1673 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1674 std::advance(it, aPosition);
1675 /* ...get an element from there... */
1676 filter = *it;
1677 /* ...and remove */
1678 filter->mInList = false;
1679 m->llUSBDeviceFilters.erase(it);
1680 }
1681
1682 /* notify the proxy (only when the filter is active) */
1683 if (m->pUSBProxyService->isActive() && filter->i_getData().mData.fActive)
1684 {
1685 ComAssertRet(filter->i_getId() != NULL, E_FAIL);
1686 m->pUSBProxyService->removeFilter(filter->i_getId());
1687 filter->i_getId() = NULL;
1688 }
1689
1690 // save the global settings; for that we should hold only the VirtualBox lock
1691 alock.release();
1692 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1693 return rc = m->pParent->i_saveSettings();
1694#else
1695 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1696 * extended error info to indicate that USB is simply not available
1697 * (w/o treating it as a failure), for example, as in OSE. */
1698 RT_NOREF(aPosition);
1699 ReturnComNotImplemented();
1700#endif
1701}
1702
1703HRESULT Host::findHostDVDDrive(const com::Utf8Str &aName,
1704 ComPtr<IMedium> &aDrive)
1705{
1706 ComObjPtr<Medium> medium;
1707 HRESULT rc = i_findHostDriveByNameOrId(DeviceType_DVD, aName, medium);
1708 if (SUCCEEDED(rc))
1709 rc = medium.queryInterfaceTo(aDrive.asOutParam());
1710 else
1711 rc = setError(rc, Medium::tr("The host DVD drive named '%s' could not be found"), aName.c_str());
1712 return rc;
1713}
1714
1715HRESULT Host::findHostFloppyDrive(const com::Utf8Str &aName, ComPtr<IMedium> &aDrive)
1716{
1717 aDrive = NULL;
1718
1719 ComObjPtr<Medium>medium;
1720
1721 HRESULT rc = i_findHostDriveByNameOrId(DeviceType_Floppy, aName, medium);
1722 if (SUCCEEDED(rc))
1723 return medium.queryInterfaceTo(aDrive.asOutParam());
1724 else
1725 return setError(rc, Medium::tr("The host floppy drive named '%s' could not be found"), aName.c_str());
1726}
1727
1728HRESULT Host::findHostNetworkInterfaceByName(const com::Utf8Str &aName,
1729 ComPtr<IHostNetworkInterface> &aNetworkInterface)
1730{
1731#ifndef VBOX_WITH_HOSTNETIF_API
1732 return E_NOTIMPL;
1733#else
1734 if (!aName.length())
1735 return E_INVALIDARG;
1736
1737 HRESULT rc = i_updateNetIfList();
1738 if (FAILED(rc))
1739 {
1740 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
1741 return rc;
1742 }
1743#if defined(RT_OS_WINDOWS)
1744 rc = i_updatePersistentConfigForHostOnlyAdapters();
1745 if (FAILED(rc))
1746 {
1747 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
1748 return rc;
1749 }
1750#endif /* defined(RT_OS_WINDOWS) */
1751
1752 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1753
1754 ComObjPtr<HostNetworkInterface> found;
1755 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1756 {
1757 Bstr n;
1758 (*it)->COMGETTER(Name)(n.asOutParam());
1759 if (n == aName)
1760 found = *it;
1761 }
1762
1763 if (!found)
1764 return setError(E_INVALIDARG,
1765 HostNetworkInterface::tr("The host network interface named '%s' could not be found"), aName.c_str());
1766
1767 return found.queryInterfaceTo(aNetworkInterface.asOutParam());
1768#endif
1769}
1770
1771HRESULT Host::findHostNetworkInterfaceById(const com::Guid &aId,
1772 ComPtr<IHostNetworkInterface> &aNetworkInterface)
1773{
1774#ifndef VBOX_WITH_HOSTNETIF_API
1775 return E_NOTIMPL;
1776#else
1777 if (!aId.isValid())
1778 return E_INVALIDARG;
1779
1780 HRESULT rc = i_updateNetIfList();
1781 if (FAILED(rc))
1782 {
1783 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
1784 return rc;
1785 }
1786#if defined(RT_OS_WINDOWS)
1787 rc = i_updatePersistentConfigForHostOnlyAdapters();
1788 if (FAILED(rc))
1789 {
1790 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
1791 return rc;
1792 }
1793#endif /* defined(RT_OS_WINDOWS) */
1794
1795 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1796
1797 ComObjPtr<HostNetworkInterface> found;
1798 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1799 {
1800 Bstr g;
1801 (*it)->COMGETTER(Id)(g.asOutParam());
1802 if (Guid(g) == aId)
1803 found = *it;
1804 }
1805
1806 if (!found)
1807 return setError(E_INVALIDARG,
1808 HostNetworkInterface::tr("The host network interface with the given GUID could not be found"));
1809 return found.queryInterfaceTo(aNetworkInterface.asOutParam());
1810
1811#endif
1812}
1813
1814HRESULT Host::findHostNetworkInterfacesOfType(HostNetworkInterfaceType_T aType,
1815 std::vector<ComPtr<IHostNetworkInterface> > &aNetworkInterfaces)
1816{
1817#ifdef VBOX_WITH_HOSTNETIF_API
1818 HRESULT rc = i_updateNetIfList();
1819 if (FAILED(rc))
1820 {
1821 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
1822 return rc;
1823 }
1824#if defined(RT_OS_WINDOWS)
1825 rc = i_updatePersistentConfigForHostOnlyAdapters();
1826 if (FAILED(rc))
1827 {
1828 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
1829 return rc;
1830 }
1831#endif /* defined(RT_OS_WINDOWS) */
1832
1833 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1834
1835 HostNetworkInterfaceList resultList;
1836 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1837 {
1838 HostNetworkInterfaceType_T t;
1839 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1840 if (FAILED(hr))
1841 return hr;
1842
1843 if (t == aType)
1844 resultList.push_back(*it);
1845 }
1846 aNetworkInterfaces.resize(resultList.size());
1847 size_t i = 0;
1848 for (HostNetworkInterfaceList::iterator it = resultList.begin(); it != resultList.end(); ++it, ++i)
1849 {
1850 (*it).queryInterfaceTo(aNetworkInterfaces[i].asOutParam());
1851 }
1852
1853 return S_OK;
1854#else
1855 return E_NOTIMPL;
1856#endif
1857}
1858
1859HRESULT Host::findUSBDeviceByAddress(const com::Utf8Str &aName,
1860 ComPtr<IHostUSBDevice> &aDevice)
1861{
1862#ifdef VBOX_WITH_USB
1863
1864 aDevice = NULL;
1865 SafeIfaceArray<IHostUSBDevice> devsvec;
1866 HRESULT rc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
1867 if (FAILED(rc))
1868 return rc;
1869
1870 for (size_t i = 0; i < devsvec.size(); ++i)
1871 {
1872 Bstr address;
1873 rc = devsvec[i]->COMGETTER(Address)(address.asOutParam());
1874 if (FAILED(rc))
1875 return rc;
1876 if (address == aName)
1877 {
1878 return (ComPtr<IHostUSBDevice>(devsvec[i]).queryInterfaceTo(aDevice.asOutParam()));
1879 }
1880 }
1881
1882 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1883 tr("Could not find a USB device with address '%s'"),
1884 aName.c_str());
1885
1886#else /* !VBOX_WITH_USB */
1887 RT_NOREF(aName, aDevice);
1888 return E_NOTIMPL;
1889#endif /* !VBOX_WITH_USB */
1890}
1891HRESULT Host::findUSBDeviceById(const com::Guid &aId,
1892 ComPtr<IHostUSBDevice> &aDevice)
1893{
1894#ifdef VBOX_WITH_USB
1895 if (!aId.isValid())
1896 return E_INVALIDARG;
1897
1898 aDevice = NULL;
1899
1900 SafeIfaceArray<IHostUSBDevice> devsvec;
1901 HRESULT rc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
1902 if (FAILED(rc))
1903 return rc;
1904
1905 for (size_t i = 0; i < devsvec.size(); ++i)
1906 {
1907 Bstr id;
1908 rc = devsvec[i]->COMGETTER(Id)(id.asOutParam());
1909 if (FAILED(rc))
1910 return rc;
1911 if (Guid(id) == aId)
1912 {
1913 return (ComPtr<IHostUSBDevice>(devsvec[i]).queryInterfaceTo(aDevice.asOutParam()));
1914 }
1915 }
1916 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1917 tr("Could not find a USB device with uuid {%RTuuid}"),
1918 aId.raw());
1919
1920#else /* !VBOX_WITH_USB */
1921 RT_NOREF(aId, aDevice);
1922 return E_NOTIMPL;
1923#endif /* !VBOX_WITH_USB */
1924}
1925
1926HRESULT Host::generateMACAddress(com::Utf8Str &aAddress)
1927{
1928 // no locking required
1929 i_generateMACAddress(aAddress);
1930 return S_OK;
1931}
1932
1933/**
1934 * Returns a list of host video capture devices (webcams, etc).
1935 *
1936 * @returns COM status code
1937 * @param aVideoInputDevices Array of interface pointers to be filled.
1938 */
1939HRESULT Host::getVideoInputDevices(std::vector<ComPtr<IHostVideoInputDevice> > &aVideoInputDevices)
1940{
1941 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1942 HostVideoInputDeviceList list;
1943
1944 HRESULT rc = HostVideoInputDevice::queryHostDevices(m->pParent, &list);
1945 if (FAILED(rc))
1946 return rc;
1947
1948 aVideoInputDevices.resize(list.size());
1949 size_t i = 0;
1950 for (HostVideoInputDeviceList::const_iterator it = list.begin(); it != list.end(); ++it, ++i)
1951 (*it).queryInterfaceTo(aVideoInputDevices[i].asOutParam());
1952
1953 return S_OK;
1954}
1955
1956HRESULT Host::addUSBDeviceSource(const com::Utf8Str &aBackend, const com::Utf8Str &aId, const com::Utf8Str &aAddress,
1957 const std::vector<com::Utf8Str> &aPropertyNames, const std::vector<com::Utf8Str> &aPropertyValues)
1958{
1959#ifdef VBOX_WITH_USB
1960 /* The USB proxy service will do the locking. */
1961 return m->pUSBProxyService->addUSBDeviceSource(aBackend, aId, aAddress, aPropertyNames, aPropertyValues);
1962#else
1963 RT_NOREF(aBackend, aId, aAddress, aPropertyNames, aPropertyValues);
1964 ReturnComNotImplemented();
1965#endif
1966}
1967
1968HRESULT Host::removeUSBDeviceSource(const com::Utf8Str &aId)
1969{
1970#ifdef VBOX_WITH_USB
1971 /* The USB proxy service will do the locking. */
1972 return m->pUSBProxyService->removeUSBDeviceSource(aId);
1973#else
1974 RT_NOREF(aId);
1975 ReturnComNotImplemented();
1976#endif
1977}
1978
1979
1980HRESULT Host::getUpdate(ComPtr<IHostUpdate> &aUpdate)
1981{
1982 HRESULT hrc = m->pHostUpdate.queryInterfaceTo(aUpdate.asOutParam());
1983 return hrc;
1984}
1985
1986
1987HRESULT Host::getHostDrives(std::vector<ComPtr<IHostDrive> > &aHostDrives)
1988{
1989 std::list<std::pair<com::Utf8Str, com::Utf8Str> > llDrivesPathsList;
1990 HRESULT hrc = i_getDrivesPathsList(llDrivesPathsList);
1991 if (SUCCEEDED(hrc))
1992 {
1993 for (std::list<std::pair<com::Utf8Str, com::Utf8Str> >::const_iterator it = llDrivesPathsList.begin();
1994 it != llDrivesPathsList.end();
1995 ++it)
1996 {
1997 ComObjPtr<HostDrive> pHostDrive;
1998 hrc = pHostDrive.createObject();
1999 if (SUCCEEDED(hrc))
2000 hrc = pHostDrive->initFromPathAndModel(it->first, it->second);
2001 if (FAILED(hrc))
2002 break;
2003 aHostDrives.push_back(pHostDrive);
2004 }
2005 }
2006 return hrc;
2007}
2008
2009
2010// public methods only for internal purposes
2011////////////////////////////////////////////////////////////////////////////////
2012
2013HRESULT Host::i_loadSettings(const settings::Host &data)
2014{
2015 HRESULT rc = S_OK;
2016#ifdef VBOX_WITH_USB
2017 AutoCaller autoCaller(this);
2018 if (FAILED(autoCaller.rc()))
2019 return autoCaller.rc();
2020
2021 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2022
2023 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
2024 it != data.llUSBDeviceFilters.end();
2025 ++it)
2026 {
2027 const settings::USBDeviceFilter &f = *it;
2028 ComObjPtr<HostUSBDeviceFilter> pFilter;
2029 pFilter.createObject();
2030 rc = pFilter->init(this, f);
2031 if (FAILED(rc))
2032 break;
2033
2034 m->llUSBDeviceFilters.push_back(pFilter);
2035 pFilter->mInList = true;
2036
2037 /* notify the proxy (only when the filter is active) */
2038 if (pFilter->i_getData().mData.fActive)
2039 {
2040 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
2041 flt->i_getId() = m->pUSBProxyService->insertFilter(&pFilter->i_getData().mUSBFilter);
2042 }
2043 }
2044
2045 rc = m->pUSBProxyService->i_loadSettings(data.llUSBDeviceSources);
2046#else
2047 RT_NOREF(data);
2048#endif /* VBOX_WITH_USB */
2049 return rc;
2050}
2051
2052HRESULT Host::i_saveSettings(settings::Host &data)
2053{
2054#ifdef VBOX_WITH_USB
2055 AutoCaller autoCaller(this);
2056 if (FAILED(autoCaller.rc()))
2057 return autoCaller.rc();
2058
2059 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2060
2061 data.llUSBDeviceFilters.clear();
2062 data.llUSBDeviceSources.clear();
2063
2064 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
2065 it != m->llUSBDeviceFilters.end();
2066 ++it)
2067 {
2068 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
2069 settings::USBDeviceFilter f;
2070 pFilter->i_saveSettings(f);
2071 data.llUSBDeviceFilters.push_back(f);
2072 }
2073
2074 return m->pUSBProxyService->i_saveSettings(data.llUSBDeviceSources);
2075#else
2076 RT_NOREF(data);
2077 return S_OK;
2078#endif /* VBOX_WITH_USB */
2079
2080}
2081
2082/**
2083 * Sets the given pointer to point to the static list of DVD or floppy
2084 * drives in the Host instance data, depending on the @a mediumType
2085 * parameter.
2086 *
2087 * This builds the list on the first call; it adds or removes host drives
2088 * that may have changed if fRefresh == true.
2089 *
2090 * The caller must hold the medium tree write lock before calling this.
2091 * To protect the list to which the caller's pointer points, the caller
2092 * must also hold that lock.
2093 *
2094 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
2095 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
2096 * @param pll Caller's pointer which gets set to the static list of host drives.
2097 * @param treeLock Reference to media tree lock, need to drop it temporarily.
2098 * @returns COM status code
2099 */
2100HRESULT Host::i_getDrives(DeviceType_T mediumType,
2101 bool fRefresh,
2102 MediaList *&pll,
2103 AutoWriteLock &treeLock)
2104{
2105 HRESULT rc = S_OK;
2106 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2107
2108 MediaList llNew;
2109 MediaList *pllCached;
2110 bool *pfListBuilt = NULL;
2111
2112 switch (mediumType)
2113 {
2114 case DeviceType_DVD:
2115 if (!m->fDVDDrivesListBuilt || fRefresh)
2116 {
2117 rc = i_buildDVDDrivesList(llNew);
2118 if (FAILED(rc))
2119 return rc;
2120 pfListBuilt = &m->fDVDDrivesListBuilt;
2121 }
2122 pllCached = &m->llDVDDrives;
2123 break;
2124
2125 case DeviceType_Floppy:
2126 if (!m->fFloppyDrivesListBuilt || fRefresh)
2127 {
2128 rc = i_buildFloppyDrivesList(llNew);
2129 if (FAILED(rc))
2130 return rc;
2131 pfListBuilt = &m->fFloppyDrivesListBuilt;
2132 }
2133 pllCached = &m->llFloppyDrives;
2134 break;
2135
2136 default:
2137 return E_INVALIDARG;
2138 }
2139
2140 if (pfListBuilt)
2141 {
2142 // a list was built in llNew above:
2143 if (!*pfListBuilt)
2144 {
2145 // this was the first call (instance bool is still false): then just copy the whole list and return
2146 *pllCached = llNew;
2147 // and mark the instance data as "built"
2148 *pfListBuilt = true;
2149 }
2150 else
2151 {
2152 // list was built, and this was a subsequent call: then compare the old and the new lists
2153
2154 // remove drives from the cached list which are no longer present
2155 for (MediaList::iterator itCached = pllCached->begin();
2156 itCached != pllCached->end();
2157 /*nothing */)
2158 {
2159 Medium *pCached = *itCached;
2160 const Utf8Str strLocationCached = pCached->i_getLocationFull();
2161 bool fFound = false;
2162 for (MediaList::iterator itNew = llNew.begin();
2163 itNew != llNew.end();
2164 ++itNew)
2165 {
2166 Medium *pNew = *itNew;
2167 const Utf8Str strLocationNew = pNew->i_getLocationFull();
2168 if (strLocationNew == strLocationCached)
2169 {
2170 fFound = true;
2171 break;
2172 }
2173 }
2174 if (!fFound)
2175 {
2176 pCached->uninit();
2177 itCached = pllCached->erase(itCached);
2178 }
2179 else
2180 ++itCached;
2181 }
2182
2183 // add drives to the cached list that are not on there yet
2184 for (MediaList::iterator itNew = llNew.begin();
2185 itNew != llNew.end();
2186 ++itNew)
2187 {
2188 Medium *pNew = *itNew;
2189 const Utf8Str strLocationNew = pNew->i_getLocationFull();
2190 bool fFound = false;
2191 for (MediaList::iterator itCached = pllCached->begin();
2192 itCached != pllCached->end();
2193 ++itCached)
2194 {
2195 Medium *pCached = *itCached;
2196 const Utf8Str strLocationCached = pCached->i_getLocationFull();
2197 if (strLocationNew == strLocationCached)
2198 {
2199 fFound = true;
2200 break;
2201 }
2202 }
2203
2204 if (!fFound)
2205 pllCached->push_back(pNew);
2206 }
2207 }
2208 }
2209
2210 // return cached list to caller
2211 pll = pllCached;
2212
2213 // Make sure the media tree lock is released before llNew is cleared,
2214 // as this usually triggers calls to uninit().
2215 treeLock.release();
2216
2217 llNew.clear();
2218
2219 treeLock.acquire();
2220
2221 return rc;
2222}
2223
2224/**
2225 * Goes through the list of host drives that would be returned by getDrives()
2226 * and looks for a host drive with the given UUID. If found, it sets pMedium
2227 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2228 *
2229 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2230 * @param uuid Medium UUID of host drive to look for.
2231 * @param fRefresh Whether to refresh the host drives list (see getDrives())
2232 * @param pMedium Medium object, if found...
2233 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2234 */
2235HRESULT Host::i_findHostDriveById(DeviceType_T mediumType,
2236 const Guid &uuid,
2237 bool fRefresh,
2238 ComObjPtr<Medium> &pMedium)
2239{
2240 MediaList *pllMedia;
2241
2242 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2243 HRESULT rc = i_getDrives(mediumType, fRefresh, pllMedia, treeLock);
2244 if (SUCCEEDED(rc))
2245 {
2246 for (MediaList::iterator it = pllMedia->begin();
2247 it != pllMedia->end();
2248 ++it)
2249 {
2250 Medium *pThis = *it;
2251 AutoCaller mediumCaller(pThis);
2252 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
2253 if (pThis->i_getId() == uuid)
2254 {
2255 pMedium = pThis;
2256 return S_OK;
2257 }
2258 }
2259 }
2260
2261 return VBOX_E_OBJECT_NOT_FOUND;
2262}
2263
2264/**
2265 * Goes through the list of host drives that would be returned by getDrives()
2266 * and looks for a host drive with the given name. If found, it sets pMedium
2267 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2268 *
2269 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2270 * @param strLocationFull Name (path) of host drive to look for.
2271 * @param fRefresh Whether to refresh the host drives list (see getDrives())
2272 * @param pMedium Medium object, if found
2273 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2274 */
2275HRESULT Host::i_findHostDriveByName(DeviceType_T mediumType,
2276 const Utf8Str &strLocationFull,
2277 bool fRefresh,
2278 ComObjPtr<Medium> &pMedium)
2279{
2280 MediaList *pllMedia;
2281
2282 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2283 HRESULT rc = i_getDrives(mediumType, fRefresh, pllMedia, treeLock);
2284 if (SUCCEEDED(rc))
2285 {
2286 for (MediaList::iterator it = pllMedia->begin();
2287 it != pllMedia->end();
2288 ++it)
2289 {
2290 Medium *pThis = *it;
2291 AutoCaller mediumCaller(pThis);
2292 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
2293 if (pThis->i_getLocationFull() == strLocationFull)
2294 {
2295 pMedium = pThis;
2296 return S_OK;
2297 }
2298 }
2299 }
2300
2301 return VBOX_E_OBJECT_NOT_FOUND;
2302}
2303
2304/**
2305 * Goes through the list of host drives that would be returned by getDrives()
2306 * and looks for a host drive with the given name, location or ID. If found,
2307 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2308 *
2309 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2310 * @param strNameOrId Name or full location or UUID of host drive to look for.
2311 * @param pMedium Medium object, if found...
2312 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2313 */
2314HRESULT Host::i_findHostDriveByNameOrId(DeviceType_T mediumType,
2315 const Utf8Str &strNameOrId,
2316 ComObjPtr<Medium> &pMedium)
2317{
2318 AutoWriteLock wlock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2319
2320 Guid uuid(strNameOrId);
2321 if (uuid.isValid() && !uuid.isZero())
2322 return i_findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
2323
2324 // string is not a syntactically valid UUID: try a name then
2325 return i_findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
2326}
2327
2328/**
2329 * Called from getDrives() to build the DVD drives list.
2330 * @param list Media list
2331 * @return
2332 */
2333HRESULT Host::i_buildDVDDrivesList(MediaList &list)
2334{
2335 HRESULT rc = S_OK;
2336
2337 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2338
2339 try
2340 {
2341#if defined(RT_OS_WINDOWS)
2342 int sz = GetLogicalDriveStrings(0, NULL);
2343 TCHAR *hostDrives = new TCHAR[sz+1];
2344 GetLogicalDriveStrings(sz, hostDrives);
2345 wchar_t driveName[3] = { '?', ':', '\0' };
2346 TCHAR *p = hostDrives;
2347 do
2348 {
2349 if (GetDriveType(p) == DRIVE_CDROM)
2350 {
2351 driveName[0] = *p;
2352 ComObjPtr<Medium> hostDVDDriveObj;
2353 hostDVDDriveObj.createObject();
2354 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
2355 list.push_back(hostDVDDriveObj);
2356 }
2357 p += _tcslen(p) + 1;
2358 }
2359 while (*p);
2360 delete[] hostDrives;
2361
2362#elif defined(RT_OS_SOLARIS)
2363# ifdef VBOX_USE_LIBHAL
2364 if (!i_getDVDInfoFromHal(list))
2365# endif
2366 {
2367 i_getDVDInfoFromDevTree(list);
2368 }
2369
2370#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
2371 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
2372 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
2373 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
2374 {
2375 ComObjPtr<Medium> hostDVDDriveObj;
2376 Utf8Str location(it->mDevice);
2377 Utf8Str description(it->mDescription);
2378 if (SUCCEEDED(rc))
2379 rc = hostDVDDriveObj.createObject();
2380 if (SUCCEEDED(rc))
2381 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
2382 if (SUCCEEDED(rc))
2383 list.push_back(hostDVDDriveObj);
2384 }
2385#elif defined(RT_OS_DARWIN)
2386 PDARWINDVD cur = DarwinGetDVDDrives();
2387 while (cur)
2388 {
2389 ComObjPtr<Medium> hostDVDDriveObj;
2390 hostDVDDriveObj.createObject();
2391 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
2392 list.push_back(hostDVDDriveObj);
2393
2394 /* next */
2395 void *freeMe = cur;
2396 cur = cur->pNext;
2397 RTMemFree(freeMe);
2398 }
2399#else
2400 /* PORTME */
2401#endif
2402 }
2403 catch(std::bad_alloc &)
2404 {
2405 rc = E_OUTOFMEMORY;
2406 }
2407 return rc;
2408}
2409
2410/**
2411 * Called from getDrives() to build the floppy drives list.
2412 * @param list
2413 * @return
2414 */
2415HRESULT Host::i_buildFloppyDrivesList(MediaList &list)
2416{
2417 HRESULT rc = S_OK;
2418
2419 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2420
2421 try
2422 {
2423#ifdef RT_OS_WINDOWS
2424 int sz = GetLogicalDriveStrings(0, NULL);
2425 TCHAR *hostDrives = new TCHAR[sz+1];
2426 GetLogicalDriveStrings(sz, hostDrives);
2427 wchar_t driveName[3] = { '?', ':', '\0' };
2428 TCHAR *p = hostDrives;
2429 do
2430 {
2431 if (GetDriveType(p) == DRIVE_REMOVABLE)
2432 {
2433 driveName[0] = *p;
2434 ComObjPtr<Medium> hostFloppyDriveObj;
2435 hostFloppyDriveObj.createObject();
2436 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
2437 list.push_back(hostFloppyDriveObj);
2438 }
2439 p += _tcslen(p) + 1;
2440 }
2441 while (*p);
2442 delete[] hostDrives;
2443#elif defined(RT_OS_LINUX)
2444 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
2445 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
2446 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
2447 {
2448 ComObjPtr<Medium> hostFloppyDriveObj;
2449 Utf8Str location(it->mDevice);
2450 Utf8Str description(it->mDescription);
2451 if (SUCCEEDED(rc))
2452 rc = hostFloppyDriveObj.createObject();
2453 if (SUCCEEDED(rc))
2454 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
2455 if (SUCCEEDED(rc))
2456 list.push_back(hostFloppyDriveObj);
2457 }
2458#else
2459 RT_NOREF(list);
2460 /* PORTME */
2461#endif
2462 }
2463 catch(std::bad_alloc &)
2464 {
2465 rc = E_OUTOFMEMORY;
2466 }
2467
2468 return rc;
2469}
2470
2471#ifdef VBOX_WITH_USB
2472USBProxyService* Host::i_usbProxyService()
2473{
2474 return m->pUSBProxyService;
2475}
2476
2477HRESULT Host::i_addChild(HostUSBDeviceFilter *pChild)
2478{
2479 AutoCaller autoCaller(this);
2480 if (FAILED(autoCaller.rc()))
2481 return autoCaller.rc();
2482
2483 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2484
2485 m->llChildren.push_back(pChild);
2486
2487 return S_OK;
2488}
2489
2490HRESULT Host::i_removeChild(HostUSBDeviceFilter *pChild)
2491{
2492 AutoCaller autoCaller(this);
2493 if (FAILED(autoCaller.rc()))
2494 return autoCaller.rc();
2495
2496 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2497
2498 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
2499 it != m->llChildren.end();
2500 ++it)
2501 {
2502 if (*it == pChild)
2503 {
2504 m->llChildren.erase(it);
2505 break;
2506 }
2507 }
2508
2509 return S_OK;
2510}
2511
2512VirtualBox* Host::i_parent()
2513{
2514 return m->pParent;
2515}
2516
2517/**
2518 * Called by setter methods of all USB device filters.
2519 */
2520HRESULT Host::i_onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2521 BOOL aActiveChanged /* = FALSE */)
2522{
2523 AutoCaller autoCaller(this);
2524 if (FAILED(autoCaller.rc()))
2525 return autoCaller.rc();
2526
2527 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2528
2529 if (aFilter->mInList)
2530 {
2531 if (aActiveChanged)
2532 {
2533 // insert/remove the filter from the proxy
2534 if (aFilter->i_getData().mData.fActive)
2535 {
2536 ComAssertRet(aFilter->i_getId() == NULL, E_FAIL);
2537 aFilter->i_getId() = m->pUSBProxyService->insertFilter(&aFilter->i_getData().mUSBFilter);
2538 }
2539 else
2540 {
2541 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
2542 m->pUSBProxyService->removeFilter(aFilter->i_getId());
2543 aFilter->i_getId() = NULL;
2544 }
2545 }
2546 else
2547 {
2548 if (aFilter->i_getData().mData.fActive)
2549 {
2550 // update the filter in the proxy
2551 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
2552 m->pUSBProxyService->removeFilter(aFilter->i_getId());
2553 aFilter->i_getId() = m->pUSBProxyService->insertFilter(&aFilter->i_getData().mUSBFilter);
2554 }
2555 }
2556
2557 // save the global settings... yeah, on every single filter property change
2558 // for that we should hold only the VirtualBox lock
2559 alock.release();
2560 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2561 return m->pParent->i_saveSettings();
2562 }
2563
2564 return S_OK;
2565}
2566
2567
2568/**
2569 * Interface for obtaining a copy of the USBDeviceFilterList,
2570 * used by the USBProxyService.
2571 *
2572 * @param aGlobalFilters Where to put the global filter list copy.
2573 * @param aMachines Where to put the machine vector.
2574 */
2575void Host::i_getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2576{
2577 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2578
2579 *aGlobalFilters = m->llUSBDeviceFilters;
2580}
2581
2582#endif /* VBOX_WITH_USB */
2583
2584// private methods
2585////////////////////////////////////////////////////////////////////////////////
2586
2587#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2588
2589/**
2590 * Helper function to get the slice number from a device path
2591 *
2592 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2593 * @returns Pointer to the slice portion of the given path.
2594 */
2595static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2596{
2597 char *pszSlice = (char *)strrchr(pszDevLinkPath, 's');
2598 char *pszDisk = (char *)strrchr(pszDevLinkPath, 'd');
2599 char *pszFound;
2600 if (pszSlice && (uintptr_t)pszSlice > (uintptr_t)pszDisk)
2601 pszFound = pszSlice;
2602 else
2603 pszFound = pszDisk;
2604
2605 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2606 return pszFound;
2607
2608 return NULL;
2609}
2610
2611/**
2612 * Walk device links and returns an allocated path for the first one in the snapshot.
2613 *
2614 * @param DevLink Handle to the device link being walked.
2615 * @param pvArg Opaque pointer that we use to point to the return
2616 * variable (char *). Caller must call RTStrFree on it.
2617 * @returns DI_WALK_TERMINATE to stop the walk.
2618 */
2619static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2620{
2621 char **ppszPath = (char **)pvArg;
2622 *ppszPath = RTStrDup(di_devlink_path(DevLink));
2623 return DI_WALK_TERMINATE;
2624}
2625
2626/**
2627 * Walk all devices in the system and enumerate CD/DVD drives.
2628 * @param Node Handle to the current node.
2629 * @param pvArg Opaque data (holds list pointer).
2630 * @returns Solaris specific code whether to continue walking or not.
2631 */
2632static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2633{
2634 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2635
2636 /*
2637 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2638 * As unfortunately the Solaris drivers only export these common properties.
2639 */
2640 int *pInt = NULL;
2641 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2642 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2643 {
2644 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2645 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2646 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2647 {
2648 char *pszProduct = NULL;
2649 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2650 {
2651 char *pszVendor = NULL;
2652 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2653 {
2654 /*
2655 * Found a DVD drive, we need to scan the minor nodes to find the correct
2656 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2657 */
2658 int Major = di_driver_major(Node);
2659 di_minor_t Minor = DI_MINOR_NIL;
2660 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2661 if (DevLink)
2662 {
2663 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2664 {
2665 dev_t Dev = di_minor_devt(Minor);
2666 if ( Major != (int)major(Dev)
2667 || di_minor_spectype(Minor) == S_IFBLK
2668 || di_minor_type(Minor) != DDM_MINOR)
2669 {
2670 continue;
2671 }
2672
2673 char *pszMinorPath = di_devfs_minor_path(Minor);
2674 if (!pszMinorPath)
2675 continue;
2676
2677 char *pszDevLinkPath = NULL;
2678 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2679 di_devfs_path_free(pszMinorPath);
2680
2681 if (pszDevLinkPath)
2682 {
2683 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2684 if ( pszSlice && !strcmp(pszSlice, "s2")
2685 && !strncmp(pszDevLinkPath, RT_STR_TUPLE("/dev/rdsk"))) /* We want only raw disks */
2686 {
2687 /*
2688 * We've got a fully qualified DVD drive. Add it to the list.
2689 */
2690 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2691 if (RT_LIKELY(pDrive))
2692 {
2693 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription),
2694 "%s %s", pszVendor, pszProduct);
2695 RTStrPurgeEncoding(pDrive->szDescription);
2696 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2697 if (*ppDrives)
2698 pDrive->pNext = *ppDrives;
2699 *ppDrives = pDrive;
2700
2701 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2702 RTStrFree(pszDevLinkPath);
2703 break;
2704 }
2705 }
2706 RTStrFree(pszDevLinkPath);
2707 }
2708 }
2709 di_devlink_fini(&DevLink);
2710 }
2711 }
2712 }
2713 }
2714 }
2715 return DI_WALK_CONTINUE;
2716}
2717
2718/**
2719 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2720 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2721 */
2722void Host::i_getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2723{
2724 PSOLARISDVD pDrives = NULL;
2725 di_node_t RootNode = di_init("/", DINFOCPYALL);
2726 if (RootNode != DI_NODE_NIL)
2727 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2728
2729 di_fini(RootNode);
2730
2731 while (pDrives)
2732 {
2733 ComObjPtr<Medium> hostDVDDriveObj;
2734 hostDVDDriveObj.createObject();
2735 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2736 list.push_back(hostDVDDriveObj);
2737
2738 void *pvDrive = pDrives;
2739 pDrives = pDrives->pNext;
2740 RTMemFree(pvDrive);
2741 }
2742}
2743
2744
2745/**
2746 * Walk all devices in the system and enumerate fixed drives.
2747 * @param Node Handle to the current node.
2748 * @param pvArg Opaque data (holds list pointer).
2749 * @returns Solaris specific code whether to continue walking or not.
2750 */
2751static int solarisWalkDeviceNodeForFixedDrive(di_node_t Node, void *pvArg) RT_NOEXCEPT
2752{
2753 PSOLARISFIXEDDISK *ppDrives = (PSOLARISFIXEDDISK *)pvArg;
2754
2755 int *pInt = NULL;
2756 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2757 && *pInt == DTYPE_DIRECT) /* Fixed drive */
2758 {
2759 char *pszProduct = NULL;
2760 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2761 {
2762 char *pszVendor = NULL;
2763 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2764 {
2765 /*
2766 * Found a fixed drive, we need to scan the minor nodes to find the correct
2767 * slice that represents the whole drive.
2768 */
2769 int Major = di_driver_major(Node);
2770 di_minor_t Minor = DI_MINOR_NIL;
2771 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2772 if (DevLink)
2773 {
2774 /*
2775 * The device name we have to select depends on drive type. For fixed drives, the
2776 * name without slice or partition should be selected, for USB flash drive the
2777 * partition 0 should be selected and slice 0 for other cases.
2778 */
2779 char *pszDisk = NULL;
2780 char *pszPartition0 = NULL;
2781 char *pszSlice0 = NULL;
2782 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2783 {
2784 dev_t Dev = di_minor_devt(Minor);
2785 if ( Major != (int)major(Dev)
2786 || di_minor_spectype(Minor) == S_IFBLK
2787 || di_minor_type(Minor) != DDM_MINOR)
2788 continue;
2789
2790 char *pszMinorPath = di_devfs_minor_path(Minor);
2791 if (!pszMinorPath)
2792 continue;
2793
2794 char *pszDevLinkPath = NULL;
2795 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2796 di_devfs_path_free(pszMinorPath);
2797
2798 if (pszDevLinkPath)
2799 {
2800 char const *pszCurSlice = strrchr(pszDevLinkPath, 's');
2801 char const *pszCurDisk = strrchr(pszDevLinkPath, 'd');
2802 char const *pszCurPart = strrchr(pszDevLinkPath, 'p');
2803 char **ppszDst = NULL;
2804 if (pszCurSlice && (uintptr_t)pszCurSlice > (uintptr_t)pszCurDisk && !strcmp(pszCurSlice, "s0"))
2805 ppszDst = &pszSlice0;
2806 else if (pszCurPart && (uintptr_t)pszCurPart > (uintptr_t)pszCurDisk && !strcmp(pszCurPart, "p0"))
2807 ppszDst = &pszPartition0;
2808 else if ( (!pszCurSlice || (uintptr_t)pszCurSlice < (uintptr_t)pszCurDisk)
2809 && (!pszCurPart || (uintptr_t)pszCurPart < (uintptr_t)pszCurDisk)
2810 && *pszDevLinkPath != '\0')
2811 ppszDst = &pszDisk;
2812 else
2813 RTStrFree(pszDevLinkPath);
2814 if (ppszDst)
2815 {
2816 if (*ppszDst != NULL)
2817 RTStrFree(*ppszDst);
2818 *ppszDst = pszDevLinkPath;
2819 }
2820 }
2821 }
2822 di_devlink_fini(&DevLink);
2823 if (pszDisk || pszPartition0 || pszSlice0)
2824 {
2825 PSOLARISFIXEDDISK pDrive = (PSOLARISFIXEDDISK)RTMemAllocZ(sizeof(*pDrive));
2826 if (RT_LIKELY(pDrive))
2827 {
2828 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2829 RTStrPurgeEncoding(pDrive->szDescription);
2830
2831 const char *pszDevPath = pszDisk ? pszDisk : pszPartition0 ? pszPartition0 : pszSlice0;
2832 int rc = RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevPath);
2833 AssertRC(rc);
2834
2835 if (*ppDrives)
2836 pDrive->pNext = *ppDrives;
2837 *ppDrives = pDrive;
2838 }
2839 RTStrFree(pszDisk);
2840 RTStrFree(pszPartition0);
2841 RTStrFree(pszSlice0);
2842 }
2843 }
2844 }
2845 }
2846 }
2847 return DI_WALK_CONTINUE;
2848}
2849
2850
2851/**
2852 * Solaris specific function to enumerate fixed drives via the device tree.
2853 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2854 *
2855 * @returns COM status, either S_OK or E_OUTOFMEMORY.
2856 * @param list Reference to list where the the path/model pairs are to
2857 * be returned.
2858 */
2859HRESULT Host::i_getFixedDrivesFromDevTree(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &list) RT_NOEXCEPT
2860{
2861 PSOLARISFIXEDDISK pDrives = NULL;
2862 di_node_t RootNode = di_init("/", DINFOCPYALL);
2863 if (RootNode != DI_NODE_NIL)
2864 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForFixedDrive);
2865 di_fini(RootNode);
2866
2867 HRESULT hrc = S_OK;
2868 try
2869 {
2870 for (PSOLARISFIXEDDISK pCurDrv = pDrives; pCurDrv; pCurDrv = pCurDrv->pNext)
2871 list.push_back(std::pair<com::Utf8Str, com::Utf8Str>(pCurDrv->szRawDiskPath, pCurDrv->szDescription));
2872 }
2873 catch (std::bad_alloc &)
2874 {
2875 LogRelFunc(("Out of memory!\n"));
2876 list.clear();
2877 hrc = E_OUTOFMEMORY;
2878 }
2879
2880 while (pDrives)
2881 {
2882 PSOLARISFIXEDDISK pFreeMe = pDrives;
2883 pDrives = pDrives->pNext;
2884 ASMCompilerBarrier();
2885 RTMemFree(pFreeMe);
2886 }
2887
2888 return hrc;
2889}
2890
2891
2892/* Solaris hosts, loading libhal at runtime */
2893
2894/**
2895 * Helper function to query the hal subsystem for information about DVD drives attached to the
2896 * system.
2897 *
2898 * @returns true if information was successfully obtained, false otherwise
2899 * @param list Reference to list where the DVDs drives are to be returned.
2900 */
2901bool Host::i_getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2902{
2903 bool halSuccess = false;
2904 DBusError dbusError;
2905 if (!gLibHalCheckPresence())
2906 return false;
2907 gDBusErrorInit(&dbusError);
2908 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2909 if (dbusConnection != 0)
2910 {
2911 LibHalContext *halContext = gLibHalCtxNew();
2912 if (halContext != 0)
2913 {
2914 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
2915 {
2916 if (gLibHalCtxInit(halContext, &dbusError))
2917 {
2918 int numDevices;
2919 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2920 "storage.drive_type", "cdrom",
2921 &numDevices, &dbusError);
2922 if (halDevices != 0)
2923 {
2924 /* Hal is installed and working, so if no devices are reported, assume
2925 that there are none. */
2926 halSuccess = true;
2927 for (int i = 0; i < numDevices; i++)
2928 {
2929 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2930 halDevices[i], "block.device", &dbusError);
2931#ifdef RT_OS_SOLARIS
2932 /* The CD/DVD ioctls work only for raw device nodes. */
2933 char *tmp = getfullrawname(devNode);
2934 gLibHalFreeString(devNode);
2935 devNode = tmp;
2936#endif
2937
2938 if (devNode != 0)
2939 {
2940// if (validateDevice(devNode, true))
2941// {
2942 Utf8Str description;
2943 char *vendor, *product;
2944 /* We do not check the error here, as this field may
2945 not even exist. */
2946 vendor = gLibHalDeviceGetPropertyString(halContext,
2947 halDevices[i], "info.vendor", 0);
2948 product = gLibHalDeviceGetPropertyString(halContext,
2949 halDevices[i], "info.product", &dbusError);
2950 if ((product != 0 && product[0] != 0))
2951 {
2952 if ((vendor != 0) && (vendor[0] != 0))
2953 {
2954 description = Utf8StrFmt("%s %s",
2955 vendor, product);
2956 }
2957 else
2958 {
2959 description = product;
2960 }
2961 ComObjPtr<Medium> hostDVDDriveObj;
2962 hostDVDDriveObj.createObject();
2963 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2964 Bstr(devNode), Bstr(description));
2965 list.push_back(hostDVDDriveObj);
2966 }
2967 else
2968 {
2969 if (product == 0)
2970 {
2971 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2972 halDevices[i], dbusError.name, dbusError.message));
2973 gDBusErrorFree(&dbusError);
2974 }
2975 ComObjPtr<Medium> hostDVDDriveObj;
2976 hostDVDDriveObj.createObject();
2977 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2978 Bstr(devNode));
2979 list.push_back(hostDVDDriveObj);
2980 }
2981 if (vendor != 0)
2982 {
2983 gLibHalFreeString(vendor);
2984 }
2985 if (product != 0)
2986 {
2987 gLibHalFreeString(product);
2988 }
2989// }
2990// else
2991// {
2992// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
2993// }
2994#ifndef RT_OS_SOLARIS
2995 gLibHalFreeString(devNode);
2996#else
2997 free(devNode);
2998#endif
2999 }
3000 else
3001 {
3002 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
3003 halDevices[i], dbusError.name, dbusError.message));
3004 gDBusErrorFree(&dbusError);
3005 }
3006 }
3007 gLibHalFreeStringArray(halDevices);
3008 }
3009 else
3010 {
3011 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
3012 gDBusErrorFree(&dbusError);
3013 }
3014 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
3015 {
3016 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
3017 dbusError.name, dbusError.message));
3018 gDBusErrorFree(&dbusError);
3019 }
3020 }
3021 else
3022 {
3023 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
3024 dbusError.name, dbusError.message));
3025 gDBusErrorFree(&dbusError);
3026 }
3027 gLibHalCtxFree(halContext);
3028 }
3029 else
3030 {
3031 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
3032 }
3033 }
3034 else
3035 {
3036 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
3037 }
3038 gDBusConnectionUnref(dbusConnection);
3039 }
3040 else
3041 {
3042 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3043 dbusError.name, dbusError.message));
3044 gDBusErrorFree(&dbusError);
3045 }
3046 return halSuccess;
3047}
3048
3049
3050/**
3051 * Helper function to query the hal subsystem for information about floppy drives attached to the
3052 * system.
3053 *
3054 * @returns true if information was successfully obtained, false otherwise
3055 * @retval list drives found will be attached to this list
3056 */
3057bool Host::i_getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
3058{
3059 bool halSuccess = false;
3060 DBusError dbusError;
3061 if (!gLibHalCheckPresence())
3062 return false;
3063 gDBusErrorInit(&dbusError);
3064 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
3065 if (dbusConnection != 0)
3066 {
3067 LibHalContext *halContext = gLibHalCtxNew();
3068 if (halContext != 0)
3069 {
3070 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
3071 {
3072 if (gLibHalCtxInit(halContext, &dbusError))
3073 {
3074 int numDevices;
3075 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
3076 "storage.drive_type", "floppy",
3077 &numDevices, &dbusError);
3078 if (halDevices != 0)
3079 {
3080 /* Hal is installed and working, so if no devices are reported, assume
3081 that there are none. */
3082 halSuccess = true;
3083 for (int i = 0; i < numDevices; i++)
3084 {
3085 char *driveType = gLibHalDeviceGetPropertyString(halContext,
3086 halDevices[i], "storage.drive_type", 0);
3087 if (driveType != 0)
3088 {
3089 if (strcmp(driveType, "floppy") != 0)
3090 {
3091 gLibHalFreeString(driveType);
3092 continue;
3093 }
3094 gLibHalFreeString(driveType);
3095 }
3096 else
3097 {
3098 /* An error occurred. The attribute "storage.drive_type"
3099 probably didn't exist. */
3100 continue;
3101 }
3102 char *devNode = gLibHalDeviceGetPropertyString(halContext,
3103 halDevices[i], "block.device", &dbusError);
3104 if (devNode != 0)
3105 {
3106// if (validateDevice(devNode, false))
3107// {
3108 Utf8Str description;
3109 char *vendor, *product;
3110 /* We do not check the error here, as this field may
3111 not even exist. */
3112 vendor = gLibHalDeviceGetPropertyString(halContext,
3113 halDevices[i], "info.vendor", 0);
3114 product = gLibHalDeviceGetPropertyString(halContext,
3115 halDevices[i], "info.product", &dbusError);
3116 if ((product != 0) && (product[0] != 0))
3117 {
3118 if ((vendor != 0) && (vendor[0] != 0))
3119 {
3120 description = Utf8StrFmt("%s %s",
3121 vendor, product);
3122 }
3123 else
3124 {
3125 description = product;
3126 }
3127 ComObjPtr<Medium> hostFloppyDrive;
3128 hostFloppyDrive.createObject();
3129 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
3130 Bstr(devNode), Bstr(description));
3131 list.push_back(hostFloppyDrive);
3132 }
3133 else
3134 {
3135 if (product == 0)
3136 {
3137 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
3138 halDevices[i], dbusError.name, dbusError.message));
3139 gDBusErrorFree(&dbusError);
3140 }
3141 ComObjPtr<Medium> hostFloppyDrive;
3142 hostFloppyDrive.createObject();
3143 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
3144 Bstr(devNode));
3145 list.push_back(hostFloppyDrive);
3146 }
3147 if (vendor != 0)
3148 {
3149 gLibHalFreeString(vendor);
3150 }
3151 if (product != 0)
3152 {
3153 gLibHalFreeString(product);
3154 }
3155// }
3156// else
3157// {
3158// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
3159// }
3160 gLibHalFreeString(devNode);
3161 }
3162 else
3163 {
3164 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
3165 halDevices[i], dbusError.name, dbusError.message));
3166 gDBusErrorFree(&dbusError);
3167 }
3168 }
3169 gLibHalFreeStringArray(halDevices);
3170 }
3171 else
3172 {
3173 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
3174 gDBusErrorFree(&dbusError);
3175 }
3176 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
3177 {
3178 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
3179 dbusError.name, dbusError.message));
3180 gDBusErrorFree(&dbusError);
3181 }
3182 }
3183 else
3184 {
3185 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
3186 dbusError.name, dbusError.message));
3187 gDBusErrorFree(&dbusError);
3188 }
3189 gLibHalCtxFree(halContext);
3190 }
3191 else
3192 {
3193 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
3194 }
3195 }
3196 else
3197 {
3198 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
3199 }
3200 gDBusConnectionUnref(dbusConnection);
3201 }
3202 else
3203 {
3204 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3205 dbusError.name, dbusError.message));
3206 gDBusErrorFree(&dbusError);
3207 }
3208 return halSuccess;
3209}
3210
3211
3212/**
3213 * Helper function to query the hal subsystem for information about fixed drives attached to the
3214 * system.
3215 *
3216 * @returns COM status code. (setError is not called on failure as we only fail
3217 * with E_OUTOFMEMORY.)
3218 * @retval S_OK on success.
3219 * @retval S_FALSE if HAL cannot be used.
3220 * @param list Reference to list to return the path/model string pairs.
3221 */
3222HRESULT Host::i_getFixedDrivesFromHal(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &list) RT_NOEXCEPT
3223{
3224 HRESULT hrc = S_FALSE;
3225 if (!gLibHalCheckPresence())
3226 return hrc;
3227
3228 DBusError dbusError;
3229 gDBusErrorInit(&dbusError);
3230 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
3231 if (dbusConnection != 0)
3232 {
3233 LibHalContext *halContext = gLibHalCtxNew();
3234 if (halContext != 0)
3235 {
3236 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
3237 {
3238 if (gLibHalCtxInit(halContext, &dbusError))
3239 {
3240 int cDevices;
3241 char **halDevices = gLibHalFindDeviceStringMatch(halContext, "storage.drive_type", "disk",
3242 &cDevices, &dbusError);
3243 if (halDevices != 0)
3244 {
3245 /* Hal is installed and working, so if no devices are reported, assume
3246 that there are none. */
3247 hrc = S_OK;
3248 for (int i = 0; i < cDevices && hrc == S_OK; i++)
3249 {
3250 char *pszDevNode = gLibHalDeviceGetPropertyString(halContext, halDevices[i], "block.device",
3251 &dbusError);
3252 /* The fixed drive ioctls work only for raw device nodes. */
3253 char *pszTmp = getfullrawname(pszDevNode);
3254 gLibHalFreeString(pszDevNode);
3255 pszDevNode = pszTmp;
3256 if (pszDevNode != 0)
3257 {
3258 /* We do not check the error here, as this field may
3259 not even exist. */
3260 char *pszVendor = gLibHalDeviceGetPropertyString(halContext, halDevices[i], "info.vendor", 0);
3261 char *pszProduct = gLibHalDeviceGetPropertyString(halContext, halDevices[i], "info.product",
3262 &dbusError);
3263 Utf8Str strDescription;
3264 if (pszProduct != NULL && pszProduct[0] != '\0')
3265 {
3266 int vrc;
3267 if (pszVendor != NULL && pszVendor[0] != '\0')
3268 vrc = strDescription.printfNoThrow("%s %s", pszVendor, pszProduct);
3269 else
3270 vrc = strDescription.assignNoThrow(pszProduct);
3271 AssertRCStmt(vrc, hrc = E_OUTOFMEMORY);
3272 }
3273 if (pszVendor != NULL)
3274 gLibHalFreeString(pszVendor);
3275 if (pszProduct != NULL)
3276 gLibHalFreeString(pszProduct);
3277
3278 /* Correct device/partition/slice already choosen. Just add it to the return list */
3279 if (hrc == S_OK)
3280 try
3281 {
3282 list.push_back(std::pair<com::Utf8Str, com::Utf8Str>(pszDevNode, strDescription));
3283 }
3284 catch (std::bad_alloc &)
3285 {
3286 AssertFailedStmt(hrc = E_OUTOFMEMORY);
3287 }
3288 gLibHalFreeString(pszDevNode);
3289 }
3290 else
3291 {
3292 LogRel(("Host::COMGETTER(HostDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
3293 halDevices[i], dbusError.name, dbusError.message));
3294 gDBusErrorFree(&dbusError);
3295 }
3296 }
3297 gLibHalFreeStringArray(halDevices);
3298 }
3299 else
3300 {
3301 LogRel(("Host::COMGETTER(HostDrives): failed to get devices with capability \"storage.disk\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
3302 gDBusErrorFree(&dbusError);
3303 }
3304 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
3305 {
3306 LogRel(("Host::COMGETTER(HostDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
3307 dbusError.name, dbusError.message));
3308 gDBusErrorFree(&dbusError);
3309 }
3310 }
3311 else
3312 {
3313 LogRel(("Host::COMGETTER(HostDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
3314 dbusError.name, dbusError.message));
3315 gDBusErrorFree(&dbusError);
3316 }
3317 gLibHalCtxFree(halContext);
3318 }
3319 else
3320 LogRel(("Host::COMGETTER(HostDrives): failed to set libhal connection to dbus.\n"));
3321 }
3322 else
3323 LogRel(("Host::COMGETTER(HostDrives): failed to get a libhal context - out of memory?\n"));
3324 gDBusConnectionUnref(dbusConnection);
3325 }
3326 else
3327 {
3328 LogRel(("Host::COMGETTER(HostDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3329 dbusError.name, dbusError.message));
3330 gDBusErrorFree(&dbusError);
3331 }
3332 return hrc;
3333}
3334
3335#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
3336
3337/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
3338#if defined(RT_OS_SOLARIS)
3339
3340/**
3341 * Helper function to parse the given mount file and add found entries
3342 */
3343void Host::i_parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
3344{
3345#ifdef RT_OS_LINUX
3346 FILE *mtab = setmntent(mountTable, "r");
3347 if (mtab)
3348 {
3349 struct mntent *mntent;
3350 char *mnt_type;
3351 char *mnt_dev;
3352 char *tmp;
3353 while ((mntent = getmntent(mtab)))
3354 {
3355 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
3356 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
3357 strcpy(mnt_type, mntent->mnt_type);
3358 strcpy(mnt_dev, mntent->mnt_fsname);
3359 // supermount fs case
3360 if (strcmp(mnt_type, "supermount") == 0)
3361 {
3362 tmp = strstr(mntent->mnt_opts, "fs=");
3363 if (tmp)
3364 {
3365 free(mnt_type);
3366 mnt_type = strdup(tmp + strlen("fs="));
3367 if (mnt_type)
3368 {
3369 tmp = strchr(mnt_type, ',');
3370 if (tmp)
3371 *tmp = '\0';
3372 }
3373 }
3374 tmp = strstr(mntent->mnt_opts, "dev=");
3375 if (tmp)
3376 {
3377 free(mnt_dev);
3378 mnt_dev = strdup(tmp + strlen("dev="));
3379 if (mnt_dev)
3380 {
3381 tmp = strchr(mnt_dev, ',');
3382 if (tmp)
3383 *tmp = '\0';
3384 }
3385 }
3386 }
3387 // use strstr here to cover things fs types like "udf,iso9660"
3388 if (strstr(mnt_type, "iso9660") == 0)
3389 {
3390 /** @todo check whether we've already got the drive in our list! */
3391 if (i_validateDevice(mnt_dev, true))
3392 {
3393 ComObjPtr<Medium> hostDVDDriveObj;
3394 hostDVDDriveObj.createObject();
3395 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
3396 list.push_back (hostDVDDriveObj);
3397 }
3398 }
3399 free(mnt_dev);
3400 free(mnt_type);
3401 }
3402 endmntent(mtab);
3403 }
3404#else // RT_OS_SOLARIS
3405 FILE *mntFile = fopen(mountTable, "r");
3406 if (mntFile)
3407 {
3408 struct mnttab mntTab;
3409 while (getmntent(mntFile, &mntTab) == 0)
3410 {
3411 const char *mountName = mntTab.mnt_special;
3412 const char *mountPoint = mntTab.mnt_mountp;
3413 const char *mountFSType = mntTab.mnt_fstype;
3414 if (mountName && mountPoint && mountFSType)
3415 {
3416 // skip devices we are not interested in
3417 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts,
3418 // proc, fd, swap)
3419 (*mountFSType && (strncmp(mountFSType, RT_STR_TUPLE("devfs")) != 0 && // skip devfs
3420 // (i.e. /devices)
3421 strncmp(mountFSType, RT_STR_TUPLE("dev")) != 0 && // skip dev (i.e. /dev)
3422 strncmp(mountFSType, RT_STR_TUPLE("lofs")) != 0))) // skip loop-back file-system (lofs)
3423 {
3424 char *rawDevName = getfullrawname((char *)mountName);
3425 if (i_validateDevice(rawDevName, true))
3426 {
3427 ComObjPtr<Medium> hostDVDDriveObj;
3428 hostDVDDriveObj.createObject();
3429 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
3430 list.push_back(hostDVDDriveObj);
3431 }
3432 free(rawDevName);
3433 }
3434 }
3435 }
3436
3437 fclose(mntFile);
3438 }
3439#endif
3440}
3441
3442/**
3443 * Helper function to check whether the given device node is a valid drive
3444 */
3445bool Host::i_validateDevice(const char *deviceNode, bool isCDROM)
3446{
3447 struct stat statInfo;
3448 bool retValue = false;
3449
3450 // sanity check
3451 if (!deviceNode)
3452 {
3453 return false;
3454 }
3455
3456 // first a simple stat() call
3457 if (stat(deviceNode, &statInfo) < 0)
3458 {
3459 return false;
3460 }
3461 else
3462 {
3463 if (isCDROM)
3464 {
3465 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
3466 {
3467 int fileHandle;
3468 // now try to open the device
3469 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
3470 if (fileHandle >= 0)
3471 {
3472 cdrom_subchnl cdChannelInfo;
3473 cdChannelInfo.cdsc_format = CDROM_MSF;
3474 // this call will finally reveal the whole truth
3475#ifdef RT_OS_LINUX
3476 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
3477 (errno == EIO) || (errno == ENOENT) ||
3478 (errno == EINVAL) || (errno == ENOMEDIUM))
3479#else
3480 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
3481 (errno == EIO) || (errno == ENOENT) ||
3482 (errno == EINVAL))
3483#endif
3484 {
3485 retValue = true;
3486 }
3487 close(fileHandle);
3488 }
3489 }
3490 } else
3491 {
3492 // floppy case
3493 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
3494 {
3495 /// @todo do some more testing, maybe a nice IOCTL!
3496 retValue = true;
3497 }
3498 }
3499 }
3500 return retValue;
3501}
3502#endif // RT_OS_SOLARIS
3503
3504#ifdef VBOX_WITH_USB
3505/**
3506 * Checks for the presence and status of the USB Proxy Service.
3507 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
3508 * warning) if the proxy service is not available due to the way the host is
3509 * configured (at present, that means that usbfs and hal/DBus are not
3510 * available on a Linux host) or E_FAIL and a corresponding error message
3511 * otherwise. Intended to be used by methods that rely on the Proxy Service
3512 * availability.
3513 *
3514 * @note This method may return a warning result code. It is recommended to use
3515 * MultiError to store the return value.
3516 *
3517 * @note Locks this object for reading.
3518 */
3519HRESULT Host::i_checkUSBProxyService()
3520{
3521 AutoCaller autoCaller(this);
3522 if (FAILED(autoCaller.rc()))
3523 return autoCaller.rc();
3524
3525 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3526
3527 AssertReturn(m->pUSBProxyService, E_FAIL);
3528 if (!m->pUSBProxyService->isActive())
3529 {
3530 /* disable the USB controller completely to avoid assertions if the
3531 * USB proxy service could not start. */
3532
3533 switch (m->pUSBProxyService->getLastError())
3534 {
3535 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
3536 return setWarning(E_FAIL,
3537 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
3538 case VERR_VUSB_USB_DEVICE_PERMISSION:
3539 return setWarning(E_FAIL,
3540 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"));
3541 case VERR_VUSB_USBFS_PERMISSION:
3542 return setWarning(E_FAIL,
3543 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"));
3544 case VINF_SUCCESS:
3545 return setWarning(E_FAIL,
3546 tr("The USB Proxy Service has not yet been ported to this host"));
3547 default:
3548 return setWarning(E_FAIL, "%s: %Rrc",
3549 tr("Could not load the Host USB Proxy service"),
3550 m->pUSBProxyService->getLastError());
3551 }
3552 }
3553
3554 return S_OK;
3555}
3556#endif /* VBOX_WITH_USB */
3557
3558HRESULT Host::i_updateNetIfList()
3559{
3560#ifdef VBOX_WITH_HOSTNETIF_API
3561 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
3562
3563 /** @todo r=klaus it would save lots of clock cycles if for concurrent
3564 * threads executing this code we'd only do one interface enumeration
3565 * and update, and let the other threads use the result as is. However
3566 * if there's a constant hammering of this method, we don't want this
3567 * to cause update starvation. */
3568 HostNetworkInterfaceList list;
3569 int rc = NetIfList(list);
3570 if (rc)
3571 {
3572 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
3573 return E_FAIL;
3574 }
3575
3576 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3577
3578 AssertReturn(m->pParent, E_FAIL);
3579 /* Make a copy as the original may be partially destroyed later. */
3580 HostNetworkInterfaceList listCopy(list);
3581 HostNetworkInterfaceList::iterator itOld, itNew;
3582# ifdef VBOX_WITH_RESOURCE_USAGE_API
3583 PerformanceCollector *aCollector = m->pParent->i_performanceCollector();
3584# endif
3585 for (itOld = m->llNetIfs.begin(); itOld != m->llNetIfs.end(); ++itOld)
3586 {
3587 bool fGone = true;
3588 Bstr nameOld;
3589 (*itOld)->COMGETTER(Name)(nameOld.asOutParam());
3590 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
3591 {
3592 Bstr nameNew;
3593 (*itNew)->COMGETTER(Name)(nameNew.asOutParam());
3594 if (nameNew == nameOld)
3595 {
3596 fGone = false;
3597 (*itNew)->uninit();
3598 listCopy.erase(itNew);
3599 break;
3600 }
3601 }
3602 if (fGone)
3603 {
3604# ifdef VBOX_WITH_RESOURCE_USAGE_API
3605 (*itOld)->i_unregisterMetrics(aCollector, this);
3606 (*itOld)->uninit();
3607# endif
3608 }
3609 }
3610 /*
3611 * Need to set the references to VirtualBox object in all interface objects
3612 * (see @bugref{6439}).
3613 */
3614 for (itNew = list.begin(); itNew != list.end(); ++itNew)
3615 (*itNew)->i_setVirtualBox(m->pParent);
3616 /* At this point listCopy will contain newly discovered interfaces only. */
3617 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
3618 {
3619 HostNetworkInterfaceType_T t;
3620 HRESULT hrc = (*itNew)->COMGETTER(InterfaceType)(&t);
3621 if (FAILED(hrc))
3622 {
3623 Bstr n;
3624 (*itNew)->COMGETTER(Name)(n.asOutParam());
3625 LogRel(("Host::updateNetIfList: failed to get interface type for %ls\n", n.raw()));
3626 }
3627 else if (t == HostNetworkInterfaceType_Bridged)
3628 {
3629# ifdef VBOX_WITH_RESOURCE_USAGE_API
3630 (*itNew)->i_registerMetrics(aCollector, this);
3631# endif
3632 }
3633 }
3634 m->llNetIfs = list;
3635 return S_OK;
3636#else
3637 return E_NOTIMPL;
3638#endif
3639}
3640
3641#ifdef VBOX_WITH_RESOURCE_USAGE_API
3642
3643void Host::i_registerDiskMetrics(PerformanceCollector *aCollector)
3644{
3645 pm::CollectorHAL *hal = aCollector->getHAL();
3646 /* Create sub metrics */
3647 Utf8StrFmt fsNameBase("FS/{%s}/Usage", "/");
3648 //Utf8StrFmt fsNameBase("Filesystem/[root]/Usage");
3649 pm::SubMetric *fsRootUsageTotal = new pm::SubMetric(fsNameBase + "/Total",
3650 "Root file system size.");
3651 pm::SubMetric *fsRootUsageUsed = new pm::SubMetric(fsNameBase + "/Used",
3652 "Root file system space currently occupied.");
3653 pm::SubMetric *fsRootUsageFree = new pm::SubMetric(fsNameBase + "/Free",
3654 "Root file system space currently empty.");
3655
3656 pm::BaseMetric *fsRootUsage = new pm::HostFilesystemUsage(hal, this,
3657 fsNameBase, "/",
3658 fsRootUsageTotal,
3659 fsRootUsageUsed,
3660 fsRootUsageFree);
3661 aCollector->registerBaseMetric(fsRootUsage);
3662
3663 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal, 0));
3664 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3665 new pm::AggregateAvg()));
3666 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3667 new pm::AggregateMin()));
3668 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3669 new pm::AggregateMax()));
3670
3671 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed, 0));
3672 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3673 new pm::AggregateAvg()));
3674 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3675 new pm::AggregateMin()));
3676 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3677 new pm::AggregateMax()));
3678
3679 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree, 0));
3680 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3681 new pm::AggregateAvg()));
3682 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3683 new pm::AggregateMin()));
3684 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3685 new pm::AggregateMax()));
3686
3687 /* For now we are concerned with the root file system only. */
3688 pm::DiskList disksUsage, disksLoad;
3689 int rc = hal->getDiskListByFs("/", disksUsage, disksLoad);
3690 if (RT_FAILURE(rc))
3691 return;
3692 pm::DiskList::iterator it;
3693 for (it = disksLoad.begin(); it != disksLoad.end(); ++it)
3694 {
3695 Utf8StrFmt strName("Disk/%s", it->c_str());
3696 pm::SubMetric *fsLoadUtil = new pm::SubMetric(strName + "/Load/Util",
3697 "Percentage of time disk was busy serving I/O requests.");
3698 pm::BaseMetric *fsLoad = new pm::HostDiskLoadRaw(hal, this, strName + "/Load",
3699 *it, fsLoadUtil);
3700 aCollector->registerBaseMetric(fsLoad);
3701
3702 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil, 0));
3703 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3704 new pm::AggregateAvg()));
3705 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3706 new pm::AggregateMin()));
3707 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3708 new pm::AggregateMax()));
3709 }
3710 for (it = disksUsage.begin(); it != disksUsage.end(); ++it)
3711 {
3712 Utf8StrFmt strName("Disk/%s", it->c_str());
3713 pm::SubMetric *fsUsageTotal = new pm::SubMetric(strName + "/Usage/Total",
3714 "Disk size.");
3715 pm::BaseMetric *fsUsage = new pm::HostDiskUsage(hal, this, strName + "/Usage",
3716 *it, fsUsageTotal);
3717 aCollector->registerBaseMetric(fsUsage);
3718
3719 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, 0));
3720 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3721 new pm::AggregateAvg()));
3722 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3723 new pm::AggregateMin()));
3724 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3725 new pm::AggregateMax()));
3726 }
3727}
3728
3729void Host::i_registerMetrics(PerformanceCollector *aCollector)
3730{
3731 pm::CollectorHAL *hal = aCollector->getHAL();
3732 /* Create sub metrics */
3733 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
3734 "Percentage of processor time spent in user mode.");
3735 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
3736 "Percentage of processor time spent in kernel mode.");
3737 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
3738 "Percentage of processor time spent idling.");
3739 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
3740 "Average of current frequency of all processors.");
3741 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
3742 "Total physical memory installed.");
3743 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
3744 "Physical memory currently occupied.");
3745 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
3746 "Physical memory currently available to applications.");
3747 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
3748 "Total physical memory used by the hypervisor.");
3749 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
3750 "Total physical memory free inside the hypervisor.");
3751 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
3752 "Total physical memory ballooned by the hypervisor.");
3753 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
3754 "Total physical memory shared between VMs.");
3755
3756
3757 /* Create and register base metrics */
3758 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, this, cpuLoadUser, cpuLoadKernel,
3759 cpuLoadIdle);
3760 aCollector->registerBaseMetric(cpuLoad);
3761 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, this, cpuMhzSM);
3762 aCollector->registerBaseMetric(cpuMhz);
3763 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, this,
3764 ramUsageTotal,
3765 ramUsageUsed,
3766 ramUsageFree);
3767 aCollector->registerBaseMetric(ramUsage);
3768 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), this,
3769 ramVMMUsed,
3770 ramVMMFree,
3771 ramVMMBallooned,
3772 ramVMMShared);
3773 aCollector->registerBaseMetric(ramVmm);
3774
3775 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
3776 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3777 new pm::AggregateAvg()));
3778 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3779 new pm::AggregateMin()));
3780 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3781 new pm::AggregateMax()));
3782
3783 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
3784 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3785 new pm::AggregateAvg()));
3786 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3787 new pm::AggregateMin()));
3788 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3789 new pm::AggregateMax()));
3790
3791 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
3792 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3793 new pm::AggregateAvg()));
3794 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3795 new pm::AggregateMin()));
3796 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3797 new pm::AggregateMax()));
3798
3799 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
3800 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3801 new pm::AggregateAvg()));
3802 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3803 new pm::AggregateMin()));
3804 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3805 new pm::AggregateMax()));
3806
3807 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
3808 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3809 new pm::AggregateAvg()));
3810 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3811 new pm::AggregateMin()));
3812 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3813 new pm::AggregateMax()));
3814
3815 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
3816 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3817 new pm::AggregateAvg()));
3818 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3819 new pm::AggregateMin()));
3820 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3821 new pm::AggregateMax()));
3822
3823 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
3824 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3825 new pm::AggregateAvg()));
3826 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3827 new pm::AggregateMin()));
3828 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3829 new pm::AggregateMax()));
3830
3831 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
3832 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3833 new pm::AggregateAvg()));
3834 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3835 new pm::AggregateMin()));
3836 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3837 new pm::AggregateMax()));
3838
3839 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
3840 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3841 new pm::AggregateAvg()));
3842 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3843 new pm::AggregateMin()));
3844 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3845 new pm::AggregateMax()));
3846
3847 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
3848 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3849 new pm::AggregateAvg()));
3850 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3851 new pm::AggregateMin()));
3852 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3853 new pm::AggregateMax()));
3854
3855 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
3856 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3857 new pm::AggregateAvg()));
3858 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3859 new pm::AggregateMin()));
3860 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3861 new pm::AggregateMax()));
3862 i_registerDiskMetrics(aCollector);
3863}
3864
3865void Host::i_unregisterMetrics(PerformanceCollector *aCollector)
3866{
3867 aCollector->unregisterMetricsFor(this);
3868 aCollector->unregisterBaseMetricsFor(this);
3869}
3870
3871#endif /* VBOX_WITH_RESOURCE_USAGE_API */
3872
3873
3874/* static */
3875void Host::i_generateMACAddress(Utf8Str &mac)
3876{
3877 /*
3878 * Our strategy is as follows: the first three bytes are our fixed
3879 * vendor ID (080027). The remaining 3 bytes will be taken from the
3880 * start of a GUID. This is a fairly safe algorithm.
3881 */
3882 Guid guid;
3883 guid.create();
3884 mac = Utf8StrFmt("080027%02X%02X%02X",
3885 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
3886}
3887
3888#ifdef RT_OS_WINDOWS
3889HRESULT Host::i_getFixedDrivesFromGlobalNamespace(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &aDriveList) RT_NOEXCEPT
3890{
3891 RTERRINFOSTATIC ErrInfo;
3892 uint32_t offError;
3893 RTVFSDIR hVfsDir;
3894 int rc = RTVfsChainOpenDir("\\\\:iprtnt:\\GLOBAL??", 0 /*fFlags*/, &hVfsDir, &offError, RTErrInfoInitStatic(&ErrInfo));
3895 if (RT_FAILURE(rc))
3896 return setError(E_FAIL, tr("Failed to open NT\\GLOBAL?? (error %Rrc)"), rc);
3897
3898 /*
3899 * Scan whole directory and find any 'PhysicalDiskX' entries. Next, combine with '\\.\'
3900 * to obtain the harddisk dev path.
3901 */
3902 size_t cbDirEntryAlloced = sizeof(RTDIRENTRYEX);
3903 PRTDIRENTRYEX pDirEntry = (PRTDIRENTRYEX)RTMemTmpAlloc(cbDirEntryAlloced);
3904 if (!pDirEntry)
3905 {
3906 RTVfsDirRelease(hVfsDir);
3907 return setError(E_OUTOFMEMORY, "Out of memory! (direntry buffer)");
3908 }
3909
3910 HRESULT hrc = S_OK;
3911 for (;;)
3912 {
3913 size_t cbDirEntry = cbDirEntryAlloced;
3914 rc = RTVfsDirReadEx(hVfsDir, pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING);
3915 if (RT_FAILURE(rc))
3916 {
3917 if (rc == VERR_BUFFER_OVERFLOW)
3918 {
3919 RTMemTmpFree(pDirEntry);
3920 cbDirEntryAlloced = RT_ALIGN_Z(RT_MIN(cbDirEntry, cbDirEntryAlloced) + 64, 64);
3921 pDirEntry = (PRTDIRENTRYEX)RTMemTmpAlloc(cbDirEntryAlloced);
3922 if (pDirEntry)
3923 continue;
3924 hrc = setError(E_OUTOFMEMORY, "Out of memory! (direntry buffer)");
3925 }
3926 else if (rc != VERR_NO_MORE_FILES)
3927 hrc = setError(VBOX_E_IPRT_ERROR, "RTVfsDirReadEx failed: %Rrc", rc);
3928 break;
3929 }
3930 if (RTStrStartsWith(pDirEntry->szName, "PhysicalDrive"))
3931 {
3932 char szPhysicalDrive[64];
3933 RTStrPrintf(szPhysicalDrive, sizeof(szPhysicalDrive), "\\\\.\\%s", pDirEntry->szName);
3934
3935 RTFILE hRawFile = NIL_RTFILE;
3936 int vrc = RTFileOpen(&hRawFile, szPhysicalDrive, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3937 if (RT_FAILURE(vrc))
3938 {
3939 try
3940 {
3941 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(szPhysicalDrive, "Unknown (Access denied)"));
3942 }
3943 catch (std::bad_alloc &)
3944 {
3945 hrc = setError(E_OUTOFMEMORY, "Out of memory");
3946 break;
3947 }
3948 continue;
3949 }
3950
3951 DWORD cbBytesReturned = 0;
3952 uint8_t abBuffer[1024];
3953 RT_ZERO(abBuffer);
3954
3955 STORAGE_PROPERTY_QUERY query;
3956 RT_ZERO(query);
3957 query.PropertyId = StorageDeviceProperty;
3958 query.QueryType = PropertyStandardQuery;
3959
3960 BOOL fRc = DeviceIoControl((HANDLE)RTFileToNative(hRawFile),
3961 IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query),
3962 abBuffer, sizeof(abBuffer), &cbBytesReturned, NULL);
3963 RTFileClose(hRawFile);
3964 char szModel[1024];
3965 if (fRc)
3966 {
3967 PSTORAGE_DEVICE_DESCRIPTOR pDevDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)abBuffer;
3968 char *pszProduct = pDevDescriptor->ProductIdOffset ? (char *)&abBuffer[pDevDescriptor->ProductIdOffset] : NULL;
3969 if (pszProduct)
3970 {
3971 RTStrPurgeEncoding(pszProduct);
3972 if (*pszProduct != '\0')
3973 {
3974 char *pszVendor = pDevDescriptor->VendorIdOffset ? (char *)&abBuffer[pDevDescriptor->VendorIdOffset] : NULL;
3975 if (pszVendor)
3976 RTStrPurgeEncoding(pszVendor);
3977 if (pszVendor && *pszVendor)
3978 RTStrPrintf(szModel, sizeof(szModel), "%s %s", pszVendor, pszProduct);
3979 else
3980 RTStrCopy(szModel, sizeof(szModel), pszProduct);
3981 }
3982 }
3983 }
3984 try
3985 {
3986 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(szPhysicalDrive, szModel));
3987 }
3988 catch (std::bad_alloc &)
3989 {
3990 hrc = setError(E_OUTOFMEMORY, "Out of memory");
3991 break;
3992 }
3993 }
3994 }
3995 if (FAILED(hrc))
3996 aDriveList.clear();
3997 RTMemTmpFree(pDirEntry);
3998 RTVfsDirRelease(hVfsDir);
3999 return hrc;
4000}
4001#endif
4002
4003/**
4004 * @throws nothing
4005 */
4006HRESULT Host::i_getDrivesPathsList(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &aDriveList) RT_NOEXCEPT
4007{
4008#ifdef RT_OS_WINDOWS
4009 return i_getFixedDrivesFromGlobalNamespace(aDriveList);
4010
4011#elif defined(RT_OS_DARWIN)
4012 /*
4013 * Get the list of fixed drives from iokit.cpp and transfer it to aDriveList.
4014 */
4015 PDARWINFIXEDDRIVE pDrives = DarwinGetFixedDrives();
4016 HRESULT hrc;
4017 try
4018 {
4019 for (PDARWINFIXEDDRIVE pCurDrv = pDrives; pCurDrv; pCurDrv = pCurDrv->pNext)
4020 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(pCurDrv->szName, pCurDrv->pszModel));
4021 hrc = S_OK;
4022 }
4023 catch (std::bad_alloc &)
4024 {
4025 aDriveList.clear();
4026 hrc = E_OUTOFMEMORY;
4027 }
4028
4029 while (pDrives)
4030 {
4031 PDARWINFIXEDDRIVE pFreeMe = pDrives;
4032 pDrives = pDrives->pNext;
4033 ASMCompilerBarrier();
4034 RTMemFree(pFreeMe);
4035 }
4036 return hrc;
4037
4038#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
4039 /*
4040 * The list of fixed drives is kept in the VBoxMainDriveInfo instance, so
4041 * update it and tranfer the info to aDriveList.
4042 *
4043 * This obviously requires us to write lock the object!
4044 */
4045 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4046 int vrc = m->hostDrives.updateFixedDrives(); /* nothrow */
4047 if (RT_FAILURE(vrc))
4048 return setErrorBoth(E_FAIL, vrc, tr("Failed to update fixed drive list (%Rrc)"), vrc);
4049
4050 try
4051 {
4052 for (DriveInfoList::const_iterator it = m->hostDrives.FixedDriveBegin(); it != m->hostDrives.FixedDriveEnd(); ++it)
4053 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(it->mDevice, it->mDescription));
4054 }
4055 catch (std::bad_alloc &)
4056 {
4057 aDriveList.clear();
4058 return E_OUTOFMEMORY;
4059 }
4060 return S_OK;
4061
4062#elif defined(RT_OS_SOLARIS)
4063 /*
4064 * We can get the info from HAL, if not present/working we'll get by
4065 * walking the device tree.
4066 */
4067# ifdef VBOX_USE_LIBHAL
4068 HRESULT hrc = i_getFixedDrivesFromHal(aDriveList);
4069 if (hrc != S_FALSE)
4070 return hrc;
4071 aDriveList.clear(); /* just in case */
4072# endif
4073 return i_getFixedDrivesFromDevTree(aDriveList);
4074
4075#else
4076 /* PORTME */
4077 RT_NOREF(aDriveList);
4078 return E_NOTIMPL;
4079#endif
4080}
4081
4082/* 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