VirtualBox

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

Last change on this file since 107437 was 107296, checked in by vboxsync, 6 weeks ago

Windows/Networking: Removed NDIS 5-based drivers, as we don't support Windows host OSes anymore which require this NDIS version -- only NDIS 6.0+ is supported now. bugref:10819

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

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