VirtualBox

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

Last change on this file since 94141 was 94141, checked in by vboxsync, 3 years ago

Main/HostImpl.cpp: nits.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette