VirtualBox

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

Last change on this file since 86186 was 85937, checked in by vboxsync, 4 years ago

Main/HosImpl.cpp: Solaris build fix. bugref:9224

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