VirtualBox

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

Last change on this file since 106297 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 153.9 KB
Line 
1/* $Id: HostImpl.cpp 106061 2024-09-16 14:03:52Z 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 if (hrc != S_OK)
936 {
937 /* fall back to NDIS5 miniport lookup (sun_VBoxNetFlt) */
938 hrc = pNc->FindComponent(L"sun_VBoxNetFlt", &pTcpIpNcc);
939 }
940# ifndef VBOX_WITH_HARDENING
941 if (hrc != S_OK)
942 {
943 /** @todo try to install the netflt from here */
944 }
945# endif
946
947# endif
948
949 if (hrc == S_OK)
950 {
951 hrc = VBoxNetCfgWinGetBindingPathEnum(pTcpIpNcc, EBP_BELOW, &pEnumBp);
952 Assert(hrc == S_OK);
953 if (hrc == S_OK)
954 {
955 hrc = VBoxNetCfgWinGetFirstBindingPath(pEnumBp, &pBp);
956 Assert(hrc == S_OK || hrc == S_FALSE);
957 while (hrc == S_OK)
958 {
959 /* S_OK == enabled, S_FALSE == disabled */
960 if (pBp->IsEnabled() == S_OK)
961 {
962 hrc = VBoxNetCfgWinGetBindingInterfaceEnum(pBp, &pEnumBi);
963 Assert(hrc == S_OK);
964 if (hrc == S_OK)
965 {
966 hrc = VBoxNetCfgWinGetFirstBindingInterface(pEnumBi, &pBi);
967 Assert(hrc == S_OK);
968 while (hrc == S_OK)
969 {
970 hrc = pBi->GetLowerComponent(&pMpNcc);
971 Assert(hrc == S_OK);
972 if (hrc == S_OK)
973 {
974 ULONG uComponentStatus;
975 hrc = pMpNcc->GetDeviceStatus(&uComponentStatus);
976 Assert(hrc == S_OK);
977 if (hrc == S_OK)
978 {
979 if (uComponentStatus == 0)
980 vboxNetWinAddComponent(&list, pMpNcc);
981 }
982 VBoxNetCfgWinReleaseRef(pMpNcc);
983 }
984 VBoxNetCfgWinReleaseRef(pBi);
985
986 hrc = VBoxNetCfgWinGetNextBindingInterface(pEnumBi, &pBi);
987 }
988 VBoxNetCfgWinReleaseRef(pEnumBi);
989 }
990 }
991 VBoxNetCfgWinReleaseRef(pBp);
992
993 hrc = VBoxNetCfgWinGetNextBindingPath(pEnumBp, &pBp);
994 }
995 VBoxNetCfgWinReleaseRef(pEnumBp);
996 }
997 VBoxNetCfgWinReleaseRef(pTcpIpNcc);
998 }
999 else
1000 {
1001 LogRel(("failed to get the oracle_VBoxNetLwf(sun_VBoxNetFlt) component, error (0x%x)\n", hrc));
1002 }
1003
1004 VBoxNetCfgWinReleaseINetCfg(pNc, FALSE);
1005 }
1006# endif /* # if defined VBOX_WITH_NETFLT */
1007
1008
1009# elif defined RT_OS_LINUX
1010 int sock = socket(AF_INET, SOCK_DGRAM, 0);
1011 if (sock >= 0)
1012 {
1013 char pBuffer[2048];
1014 struct ifconf ifConf;
1015 ifConf.ifc_len = sizeof(pBuffer);
1016 ifConf.ifc_buf = pBuffer;
1017 if (ioctl(sock, SIOCGIFCONF, &ifConf) >= 0)
1018 {
1019 for (struct ifreq *pReq = ifConf.ifc_req; (char*)pReq < pBuffer + ifConf.ifc_len; pReq++)
1020 {
1021 if (ioctl(sock, SIOCGIFHWADDR, pReq) >= 0)
1022 {
1023 if (pReq->ifr_hwaddr.sa_family == ARPHRD_ETHER)
1024 {
1025 RTUUID uuid;
1026 Assert(sizeof(uuid) <= sizeof(*pReq));
1027 memcpy(&uuid, pReq, sizeof(uuid));
1028
1029 ComObjPtr<HostNetworkInterface> IfObj;
1030 IfObj.createObject();
1031 if (SUCCEEDED(IfObj->init(Bstr(pReq->ifr_name), Guid(uuid), HostNetworkInterfaceType_Bridged)))
1032 list.push_back(IfObj);
1033 }
1034 }
1035 }
1036 }
1037 close(sock);
1038 }
1039# endif /* RT_OS_LINUX */
1040
1041 aNetworkInterfaces.resize(list.size());
1042 size_t i = 0;
1043 for (std::list<ComObjPtr<HostNetworkInterface> >::const_iterator it = list.begin(); it != list.end(); ++it, ++i)
1044 aNetworkInterfaces[i] = *it;
1045
1046 return S_OK;
1047# endif
1048#else
1049 /* Not implemented / supported on this platform. */
1050 RT_NOREF(aNetworkInterfaces);
1051 ReturnComNotImplemented();
1052#endif
1053}
1054
1055HRESULT Host::getAudioDevices(std::vector<ComPtr<IHostAudioDevice> > &aAudioDevices)
1056{
1057 RT_NOREF(aAudioDevices);
1058 ReturnComNotImplemented();
1059}
1060
1061HRESULT Host::getUSBDevices(std::vector<ComPtr<IHostUSBDevice> > &aUSBDevices)
1062{
1063#ifdef VBOX_WITH_USB
1064 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1065
1066 MultiResult mrc = i_checkUSBProxyService();
1067 if (FAILED(mrc) || SUCCEEDED_WARNING(mrc))
1068 return mrc;
1069
1070 return m->pUSBProxyService->getDeviceCollection(aUSBDevices);
1071#else
1072 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1073 * extended error info to indicate that USB is simply not available
1074 * (w/o treating it as a failure), for example, as in OSE. */
1075 RT_NOREF(aUSBDevices);
1076 ReturnComNotImplemented();
1077#endif
1078}
1079
1080/**
1081 * This method return the list of registered name servers
1082 */
1083HRESULT Host::getNameServers(std::vector<com::Utf8Str> &aNameServers)
1084{
1085 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1086 return m->hostDnsMonitorProxy.GetNameServers(aNameServers);
1087}
1088
1089
1090/**
1091 * This method returns the domain name of the host
1092 */
1093HRESULT Host::getDomainName(com::Utf8Str &aDomainName)
1094{
1095 /** @todo XXX: note here should be synchronization with thread polling state
1096 * changes in name resolving system on host */
1097 return m->hostDnsMonitorProxy.GetDomainName(&aDomainName);
1098}
1099
1100
1101/**
1102 * This method returns the search string.
1103 */
1104HRESULT Host::getSearchStrings(std::vector<com::Utf8Str> &aSearchStrings)
1105{
1106 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1107 return m->hostDnsMonitorProxy.GetSearchStrings(aSearchStrings);
1108}
1109
1110HRESULT Host::getUSBDeviceFilters(std::vector<ComPtr<IHostUSBDeviceFilter> > &aUSBDeviceFilters)
1111{
1112#ifdef VBOX_WITH_USB
1113 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1114
1115 MultiResult mrc = i_checkUSBProxyService();
1116 if (FAILED(mrc))
1117 return mrc;
1118
1119 aUSBDeviceFilters.resize(m->llUSBDeviceFilters.size());
1120 size_t i = 0;
1121 for (USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin(); it != m->llUSBDeviceFilters.end(); ++it, ++i)
1122 (*it).queryInterfaceTo(aUSBDeviceFilters[i].asOutParam());
1123
1124 return mrc;
1125#else
1126 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1127 * extended error info to indicate that USB is simply not available
1128 * (w/o treating it as a failure), for example, as in OSE. */
1129 RT_NOREF(aUSBDeviceFilters);
1130 ReturnComNotImplemented();
1131#endif
1132}
1133
1134/**
1135 * Returns the number of installed logical processors
1136 *
1137 * @returns COM status code
1138 * @param aCount address of result variable
1139 */
1140
1141HRESULT Host::getProcessorCount(ULONG *aCount)
1142{
1143 // no locking required
1144
1145 *aCount = RTMpGetPresentCount();
1146 return S_OK;
1147}
1148
1149/**
1150 * Returns the number of online logical processors
1151 *
1152 * @returns COM status code
1153 * @param aCount address of result variable
1154 */
1155HRESULT Host::getProcessorOnlineCount(ULONG *aCount)
1156{
1157 // no locking required
1158
1159 *aCount = RTMpGetOnlineCount();
1160 return S_OK;
1161}
1162
1163/**
1164 * Returns the number of installed physical processor cores.
1165 *
1166 * @returns COM status code
1167 * @param aCount address of result variable
1168 */
1169HRESULT Host::getProcessorCoreCount(ULONG *aCount)
1170{
1171 // no locking required
1172
1173 *aCount = RTMpGetPresentCoreCount();
1174 return S_OK;
1175}
1176
1177/**
1178 * Returns the number of installed physical processor cores.
1179 *
1180 * @returns COM status code
1181 * @param aCount address of result variable
1182 */
1183HRESULT Host::getProcessorOnlineCoreCount(ULONG *aCount)
1184{
1185 // no locking required
1186
1187 *aCount = RTMpGetOnlineCoreCount();
1188 return S_OK;
1189}
1190
1191/**
1192 * Returns the (approximate) maximum speed of the given host CPU in MHz
1193 *
1194 * @returns COM status code
1195 * @param aCpuId id to get info for.
1196 * @param aSpeed address of result variable, speed is 0 if unknown or aCpuId
1197 * is invalid.
1198 */
1199HRESULT Host::getProcessorSpeed(ULONG aCpuId,
1200 ULONG *aSpeed)
1201{
1202 // no locking required
1203
1204 *aSpeed = RTMpGetMaxFrequency(aCpuId);
1205 return S_OK;
1206}
1207
1208/**
1209 * Returns a description string for the host CPU
1210 *
1211 * @returns COM status code
1212 * @param aCpuId id to get info for.
1213 * @param aDescription address of result variable, empty string if not known
1214 * or aCpuId is invalid.
1215 */
1216HRESULT Host::getProcessorDescription(ULONG aCpuId, com::Utf8Str &aDescription)
1217{
1218 // no locking required
1219
1220 int vrc = aDescription.reserveNoThrow(80);
1221 if (RT_SUCCESS(vrc))
1222 {
1223 vrc = RTMpGetDescription(aCpuId, aDescription.mutableRaw(), aDescription.capacity());
1224 if (RT_SUCCESS(vrc))
1225 {
1226 aDescription.jolt();
1227 return S_OK;
1228 }
1229 }
1230 return setErrorVrc(vrc);
1231}
1232
1233/**
1234 * Updates fVTSupported, fNestedPagingSupported, fUnrestrictedGuestSupported,
1235 * fVirtVmsaveVmload and fNestedHWVirtSupported with info from SUPR3QueryVTCaps().
1236 *
1237 * This is repeated till we successfully open the support driver, in case it
1238 * is loaded after VBoxSVC starts.
1239 */
1240void Host::i_updateProcessorFeatures()
1241{
1242#ifndef RT_ARCH_ARM64
1243 /* Perhaps the driver is available now... */
1244 int vrc = SUPR3InitEx(SUPR3INIT_F_LIMITED, NULL);
1245 if (RT_SUCCESS(vrc))
1246 {
1247 uint32_t fVTCaps;
1248 vrc = SUPR3QueryVTCaps(&fVTCaps);
1249 AssertMsg(RT_SUCCESS(vrc) || vrc == VERR_SUP_DRIVERLESS, ("SUPR3QueryVTCaps failed vrc=%Rrc\n", vrc));
1250
1251 SUPR3Term(false);
1252
1253 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
1254 if (RT_FAILURE(vrc))
1255 {
1256 fVTCaps = 0;
1257 if (vrc != VERR_SUP_DRIVERLESS)
1258 LogRel(("SUPR0QueryVTCaps -> %Rrc\n", vrc));
1259# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) /* Preserve detected VT-x/AMD-V support for show. */
1260 else
1261 fVTCaps = m->fVTSupported ? SUPVTCAPS_AMD_V | SUPVTCAPS_VT_X : 0;
1262# endif
1263 }
1264 m->fVTSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VT_X)) != 0;
1265 m->fNestedPagingSupported = (fVTCaps & SUPVTCAPS_NESTED_PAGING) != 0;
1266 m->fUnrestrictedGuestSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VTX_UNRESTRICTED_GUEST)) != 0;
1267 m->fNestedHWVirtSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_NESTED_PAGING))
1268 == (SUPVTCAPS_AMD_V | SUPVTCAPS_NESTED_PAGING)
1269 || (fVTCaps & ( SUPVTCAPS_VT_X | SUPVTCAPS_NESTED_PAGING
1270 | SUPVTCAPS_VTX_UNRESTRICTED_GUEST | SUPVTCAPS_VTX_VMCS_SHADOWING))
1271 == ( SUPVTCAPS_VT_X | SUPVTCAPS_NESTED_PAGING
1272 | SUPVTCAPS_VTX_UNRESTRICTED_GUEST | SUPVTCAPS_VTX_VMCS_SHADOWING);
1273 m->fVirtVmsaveVmload = (fVTCaps & SUPVTCAPS_AMDV_VIRT_VMSAVE_VMLOAD) != 0;
1274 m->fRecheckVTSupported = false; /* No need to try again, we cached everything. */
1275 }
1276#endif
1277}
1278
1279/**
1280 * Returns whether a host processor feature is supported or not
1281 *
1282 * @returns COM status code
1283 * @param aFeature to query.
1284 * @param aSupported supported bool result variable
1285 */
1286HRESULT Host::getProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
1287{
1288 /* Validate input. */
1289 switch (aFeature)
1290 {
1291 case ProcessorFeature_HWVirtEx:
1292 case ProcessorFeature_PAE:
1293 case ProcessorFeature_LongMode:
1294 case ProcessorFeature_NestedPaging:
1295 case ProcessorFeature_UnrestrictedGuest:
1296 case ProcessorFeature_NestedHWVirt:
1297 case ProcessorFeature_VirtVmsaveVmload:
1298 break;
1299 default:
1300 return setError(E_INVALIDARG, tr("The aFeature value %d (%#x) is out of range."), (int)aFeature, (int)aFeature);
1301 }
1302
1303 /* Do the job. */
1304 AutoCaller autoCaller(this);
1305 HRESULT hrc = autoCaller.hrc();
1306 if (SUCCEEDED(hrc))
1307 {
1308 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1309
1310 if ( m->fRecheckVTSupported
1311 && ( aFeature == ProcessorFeature_HWVirtEx
1312 || aFeature == ProcessorFeature_NestedPaging
1313 || aFeature == ProcessorFeature_UnrestrictedGuest
1314 || aFeature == ProcessorFeature_NestedHWVirt
1315 || aFeature == ProcessorFeature_VirtVmsaveVmload)
1316 )
1317 {
1318 alock.release();
1319 i_updateProcessorFeatures();
1320 alock.acquire();
1321 }
1322
1323 switch (aFeature)
1324 {
1325 case ProcessorFeature_HWVirtEx:
1326 *aSupported = m->fVTSupported;
1327 break;
1328
1329 case ProcessorFeature_PAE:
1330 *aSupported = m->fPAESupported;
1331 break;
1332
1333 case ProcessorFeature_LongMode:
1334 *aSupported = m->fLongModeSupported;
1335 break;
1336
1337 case ProcessorFeature_NestedPaging:
1338 *aSupported = m->fNestedPagingSupported;
1339 break;
1340
1341 case ProcessorFeature_UnrestrictedGuest:
1342 *aSupported = m->fUnrestrictedGuestSupported;
1343 break;
1344
1345 case ProcessorFeature_NestedHWVirt:
1346 *aSupported = m->fNestedHWVirtSupported;
1347 break;
1348
1349 case ProcessorFeature_VirtVmsaveVmload:
1350 *aSupported = m->fVirtVmsaveVmload;
1351 break;
1352
1353 default:
1354 AssertFailed();
1355 }
1356 }
1357 return hrc;
1358}
1359
1360/**
1361 * Returns the amount of installed system memory in megabytes
1362 *
1363 * @returns COM status code
1364 * @param aSize address of result variable
1365 */
1366HRESULT Host::getMemorySize(ULONG *aSize)
1367{
1368 // no locking required
1369
1370 uint64_t cb;
1371 int vrc = RTSystemQueryTotalRam(&cb);
1372 if (RT_FAILURE(vrc))
1373 return E_FAIL;
1374 *aSize = (ULONG)(cb / _1M);
1375 return S_OK;
1376}
1377
1378/**
1379 * Returns the current system memory free space in megabytes
1380 *
1381 * @returns COM status code
1382 * @param aAvailable address of result variable
1383 */
1384HRESULT Host::getMemoryAvailable(ULONG *aAvailable)
1385{
1386 // no locking required
1387
1388 uint64_t cb;
1389 int vrc = RTSystemQueryAvailableRam(&cb);
1390 if (RT_FAILURE(vrc))
1391 return E_FAIL;
1392 *aAvailable = (ULONG)(cb / _1M);
1393 return S_OK;
1394}
1395
1396/**
1397 * Returns the name string of the host operating system
1398 *
1399 * @returns COM status code
1400 * @param aOperatingSystem result variable
1401 */
1402HRESULT Host::getOperatingSystem(com::Utf8Str &aOperatingSystem)
1403{
1404 // no locking required
1405
1406 char szOSName[80];
1407 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1408 if (RT_FAILURE(vrc))
1409 return E_FAIL; /** @todo error reporting? */
1410 aOperatingSystem = Utf8Str(szOSName);
1411 return S_OK;
1412}
1413
1414/**
1415 * Returns the version string of the host operating system
1416 *
1417 * @returns COM status code
1418 * @param aVersion address of result variable
1419 */
1420HRESULT Host::getOSVersion(com::Utf8Str &aVersion)
1421{
1422 // no locking required
1423
1424 /* Get the OS release. Reserve some buffer space for the service pack. */
1425 char szOSRelease[128];
1426 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1427 if (RT_FAILURE(vrc))
1428 return E_FAIL; /** @todo error reporting? */
1429
1430 /* Append the service pack if present. */
1431 char szOSServicePack[80];
1432 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1433 if (RT_FAILURE(vrc))
1434 {
1435 if (vrc != VERR_NOT_SUPPORTED)
1436 return E_FAIL; /** @todo error reporting? */
1437 szOSServicePack[0] = '\0';
1438 }
1439 if (szOSServicePack[0] != '\0')
1440 {
1441 char *psz = strchr(szOSRelease, '\0');
1442 RTStrPrintf(psz, (size_t)(&szOSRelease[sizeof(szOSRelease)] - psz), "sp%s", szOSServicePack);
1443 }
1444
1445 aVersion = szOSRelease;
1446 return S_OK;
1447}
1448
1449/**
1450 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1451 *
1452 * @returns COM status code
1453 * @param aUTCTime address of result variable
1454 */
1455HRESULT Host::getUTCTime(LONG64 *aUTCTime)
1456{
1457 // no locking required
1458
1459 RTTIMESPEC now;
1460 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1461
1462 return S_OK;
1463}
1464
1465HRESULT Host::createHostOnlyNetworkInterface(ComPtr<IHostNetworkInterface> &aHostInterface,
1466 ComPtr<IProgress> &aProgress)
1467
1468{
1469#ifdef VBOX_WITH_HOSTNETIF_API
1470 /* No need to lock anything. If there ever will - watch out, the function
1471 * called below grabs the VirtualBox lock. */
1472
1473 int vrc = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostInterface.asOutParam(), aProgress.asOutParam());
1474 if (RT_SUCCESS(vrc))
1475 {
1476 if (aHostInterface.isNull())
1477 return setError(E_FAIL,
1478 tr("Unable to create a host network interface"));
1479
1480# if !defined(RT_OS_WINDOWS)
1481 Bstr tmpAddr, tmpMask, tmpName;
1482 HRESULT hrc;
1483 hrc = aHostInterface->COMGETTER(Name)(tmpName.asOutParam());
1484 ComAssertComRCRet(hrc, hrc);
1485 hrc = aHostInterface->COMGETTER(IPAddress)(tmpAddr.asOutParam());
1486 ComAssertComRCRet(hrc, hrc);
1487 hrc = aHostInterface->COMGETTER(NetworkMask)(tmpMask.asOutParam());
1488 ComAssertComRCRet(hrc, hrc);
1489
1490 /*
1491 * We need to write the default IP address and mask to extra data now,
1492 * so the interface gets re-created after vboxnetadp.ko reload.
1493 * Note that we avoid calling EnableStaticIpConfig since it would
1494 * change the address on host's interface as well and we want to
1495 * postpone the change until VM actually starts.
1496 */
1497 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", tmpName.raw()).raw(),
1498 tmpAddr.raw());
1499 ComAssertComRCRet(hrc, hrc);
1500
1501 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", tmpName.raw()).raw(),
1502 tmpMask.raw());
1503 ComAssertComRCRet(hrc, hrc);
1504# endif /* !defined(RT_OS_WINDOWS) */
1505 }
1506
1507 return S_OK;
1508#else
1509 RT_NOREF(aHostInterface, aProgress);
1510 return E_NOTIMPL;
1511#endif
1512}
1513
1514
1515#ifdef RT_OS_WINDOWS
1516HRESULT Host::i_removePersistentConfig(const Bstr &bstrGuid)
1517{
1518 HRESULT hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/Name", bstrGuid.raw()).raw(), NULL);
1519 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPAddress", bstrGuid.raw()).raw(), NULL);
1520 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPNetMask", bstrGuid.raw()).raw(), NULL);
1521 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPV6Address", bstrGuid.raw()).raw(), NULL);
1522 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPV6PrefixLen", bstrGuid.raw()).raw(), NULL);
1523 return hrc;
1524}
1525#endif /* RT_OS_WINDOWS */
1526
1527HRESULT Host::removeHostOnlyNetworkInterface(const com::Guid &aId,
1528 ComPtr<IProgress> &aProgress)
1529
1530{
1531#ifdef VBOX_WITH_HOSTNETIF_API
1532 /* No need to lock anything, the code below does not touch the state
1533 * of the host object. If that ever changes then check for lock order
1534 * violations with the called functions. */
1535
1536 Bstr name;
1537 HRESULT hrc;
1538
1539 /* first check whether an interface with the given name already exists */
1540 {
1541 ComPtr<IHostNetworkInterface> iface;
1542 hrc = findHostNetworkInterfaceById(aId, iface);
1543 if (FAILED(hrc))
1544 return setError(VBOX_E_OBJECT_NOT_FOUND,
1545 tr("Host network interface with UUID {%RTuuid} does not exist"),
1546 Guid(aId).raw());
1547 hrc = iface->COMGETTER(Name)(name.asOutParam());
1548 ComAssertComRCRet(hrc, hrc);
1549 }
1550
1551 int vrc = NetIfRemoveHostOnlyNetworkInterface(m->pParent, aId, aProgress.asOutParam());
1552 if (RT_SUCCESS(vrc))
1553 {
1554 /* Drop configuration parameters for removed interface */
1555#ifdef RT_OS_WINDOWS
1556 hrc = i_removePersistentConfig(Utf8StrFmt("%RTuuid", &aId));
1557 if (FAILED(hrc))
1558 LogRel(("i_removePersistentConfig(%RTuuid) failed with 0x%x\n", &aId, hrc));
1559#else /* !RT_OS_WINDOWS */
1560 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1561 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1562 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1563 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1564#endif /* !RT_OS_WINDOWS */
1565
1566 return S_OK;
1567 }
1568
1569 return vrc == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1570#else
1571 RT_NOREF(aId, aProgress);
1572 return E_NOTIMPL;
1573#endif
1574}
1575
1576HRESULT Host::createUSBDeviceFilter(const com::Utf8Str &aName,
1577 ComPtr<IHostUSBDeviceFilter> &aFilter)
1578{
1579#ifdef VBOX_WITH_USB
1580
1581 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1582
1583 ComObjPtr<HostUSBDeviceFilter> filter;
1584 filter.createObject();
1585 HRESULT hrc = filter->init(this, Bstr(aName).raw());
1586 ComAssertComRCRet(hrc, hrc);
1587 hrc = filter.queryInterfaceTo(aFilter.asOutParam());
1588 AssertComRCReturn(hrc, hrc);
1589 return S_OK;
1590#else
1591 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1592 * extended error info to indicate that USB is simply not available
1593 * (w/o treating it as a failure), for example, as in OSE. */
1594 RT_NOREF(aName, aFilter);
1595 ReturnComNotImplemented();
1596#endif
1597}
1598
1599HRESULT Host::insertUSBDeviceFilter(ULONG aPosition,
1600 const ComPtr<IHostUSBDeviceFilter> &aFilter)
1601{
1602#ifdef VBOX_WITH_USB
1603 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1604
1605 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1606
1607 MultiResult hrcMult = i_checkUSBProxyService();
1608 if (FAILED(hrcMult))
1609 return hrcMult;
1610
1611 ComObjPtr<HostUSBDeviceFilter> pFilter;
1612 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1613 it != m->llChildren.end();
1614 ++it)
1615 {
1616 if (*it == aFilter)
1617 {
1618 pFilter = *it;
1619 break;
1620 }
1621 }
1622 if (pFilter.isNull())
1623 return setError(VBOX_E_INVALID_OBJECT_STATE,
1624 tr("The given USB device filter is not created within this VirtualBox instance"));
1625
1626 if (pFilter->mInList)
1627 return setError(E_INVALIDARG,
1628 tr("The given USB device filter is already in the list"));
1629
1630 /* iterate to the position... */
1631 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1632 std::advance(itPos, aPosition);
1633 /* ...and insert */
1634 m->llUSBDeviceFilters.insert(itPos, pFilter);
1635 pFilter->mInList = true;
1636
1637 /* notify the proxy (only when the filter is active) */
1638 if ( m->pUSBProxyService->isActive()
1639 && pFilter->i_getData().mData.fActive)
1640 {
1641 ComAssertRet(pFilter->i_getId() == NULL, E_FAIL);
1642 pFilter->i_getId() = m->pUSBProxyService->insertFilter(&pFilter->i_getData().mUSBFilter);
1643 }
1644
1645 // save the global settings; for that we should hold only the VirtualBox lock
1646 alock.release();
1647 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1648 return hrcMult = m->pParent->i_saveSettings();
1649#else
1650
1651 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1652 * extended error info to indicate that USB is simply not available
1653 * (w/o treating it as a failure), for example, as in OSE. */
1654 RT_NOREF(aPosition, aFilter);
1655 ReturnComNotImplemented();
1656#endif
1657}
1658
1659HRESULT Host::removeUSBDeviceFilter(ULONG aPosition)
1660{
1661#ifdef VBOX_WITH_USB
1662
1663 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1664 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1665
1666 MultiResult hrcMult = i_checkUSBProxyService();
1667 if (FAILED(hrcMult))
1668 return hrcMult;
1669
1670 if (!m->llUSBDeviceFilters.size())
1671 return setError(E_INVALIDARG,
1672 tr("The USB device filter list is empty"));
1673
1674 if (aPosition >= m->llUSBDeviceFilters.size())
1675 return setError(E_INVALIDARG,
1676 tr("Invalid position: %lu (must be in range [0, %lu])"),
1677 aPosition, m->llUSBDeviceFilters.size() - 1);
1678
1679 ComObjPtr<HostUSBDeviceFilter> filter;
1680 {
1681 /* iterate to the position... */
1682 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1683 std::advance(it, aPosition);
1684 /* ...get an element from there... */
1685 filter = *it;
1686 /* ...and remove */
1687 filter->mInList = false;
1688 m->llUSBDeviceFilters.erase(it);
1689 }
1690
1691 /* notify the proxy (only when the filter is active) */
1692 if (m->pUSBProxyService->isActive() && filter->i_getData().mData.fActive)
1693 {
1694 ComAssertRet(filter->i_getId() != NULL, E_FAIL);
1695 m->pUSBProxyService->removeFilter(filter->i_getId());
1696 filter->i_getId() = NULL;
1697 }
1698
1699 // save the global settings; for that we should hold only the VirtualBox lock
1700 alock.release();
1701 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1702 return hrcMult = m->pParent->i_saveSettings();
1703#else
1704 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1705 * extended error info to indicate that USB is simply not available
1706 * (w/o treating it as a failure), for example, as in OSE. */
1707 RT_NOREF(aPosition);
1708 ReturnComNotImplemented();
1709#endif
1710}
1711
1712HRESULT Host::findHostDVDDrive(const com::Utf8Str &aName,
1713 ComPtr<IMedium> &aDrive)
1714{
1715 ComObjPtr<Medium> medium;
1716 HRESULT hrc = i_findHostDriveByNameOrId(DeviceType_DVD, aName, medium);
1717 if (SUCCEEDED(hrc))
1718 hrc = medium.queryInterfaceTo(aDrive.asOutParam());
1719 else
1720 hrc = setError(hrc, tr("The host DVD drive named '%s' could not be found"), aName.c_str());
1721 return hrc;
1722}
1723
1724HRESULT Host::findHostFloppyDrive(const com::Utf8Str &aName, ComPtr<IMedium> &aDrive)
1725{
1726 aDrive = NULL;
1727
1728 ComObjPtr<Medium>medium;
1729
1730 HRESULT hrc = i_findHostDriveByNameOrId(DeviceType_Floppy, aName, medium);
1731 if (SUCCEEDED(hrc))
1732 return medium.queryInterfaceTo(aDrive.asOutParam());
1733 return setError(hrc, tr("The host floppy drive named '%s' could not be found"), aName.c_str());
1734}
1735
1736HRESULT Host::findHostNetworkInterfaceByName(const com::Utf8Str &aName,
1737 ComPtr<IHostNetworkInterface> &aNetworkInterface)
1738{
1739#ifndef VBOX_WITH_HOSTNETIF_API
1740 RT_NOREF(aName, aNetworkInterface);
1741 return E_NOTIMPL;
1742#else
1743 if (!aName.length())
1744 return E_INVALIDARG;
1745
1746 HRESULT hrc = i_updateNetIfList();
1747 if (FAILED(hrc))
1748 {
1749 Log(("Failed to update host network interface list with hrc=%Rhrc\n", hrc));
1750 return hrc;
1751 }
1752#if defined(RT_OS_WINDOWS)
1753 hrc = i_updatePersistentConfigForHostOnlyAdapters();
1754 if (FAILED(hrc))
1755 {
1756 LogRel(("Failed to update persistent config for host-only adapters with hrc=%Rhrc\n", hrc));
1757 return hrc;
1758 }
1759#endif /* defined(RT_OS_WINDOWS) */
1760
1761 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1762
1763 ComObjPtr<HostNetworkInterface> found;
1764 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1765 {
1766 Bstr n;
1767 (*it)->COMGETTER(Name)(n.asOutParam());
1768 if (n == aName)
1769 found = *it;
1770 }
1771
1772 if (!found)
1773 return setError(E_INVALIDARG,
1774 tr("The host network interface named '%s' could not be found"), aName.c_str());
1775
1776 return found.queryInterfaceTo(aNetworkInterface.asOutParam());
1777#endif
1778}
1779
1780HRESULT Host::findHostNetworkInterfaceById(const com::Guid &aId,
1781 ComPtr<IHostNetworkInterface> &aNetworkInterface)
1782{
1783#ifndef VBOX_WITH_HOSTNETIF_API
1784 RT_NOREF(aId, aNetworkInterface);
1785 return E_NOTIMPL;
1786#else
1787 if (!aId.isValid())
1788 return E_INVALIDARG;
1789
1790 HRESULT hrc = i_updateNetIfList();
1791 if (FAILED(hrc))
1792 {
1793 Log(("Failed to update host network interface list with hrc=%Rhrc\n", hrc));
1794 return hrc;
1795 }
1796#if defined(RT_OS_WINDOWS)
1797 hrc = i_updatePersistentConfigForHostOnlyAdapters();
1798 if (FAILED(hrc))
1799 {
1800 LogRel(("Failed to update persistent config for host-only adapters with hrc=%Rhrc\n", hrc));
1801 return hrc;
1802 }
1803#endif /* defined(RT_OS_WINDOWS) */
1804
1805 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1806
1807 ComObjPtr<HostNetworkInterface> found;
1808 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1809 {
1810 Bstr g;
1811 (*it)->COMGETTER(Id)(g.asOutParam());
1812 if (Guid(g) == aId)
1813 found = *it;
1814 }
1815
1816 if (!found)
1817 return setError(E_INVALIDARG,
1818 tr("The host network interface with the given GUID could not be found"));
1819 return found.queryInterfaceTo(aNetworkInterface.asOutParam());
1820
1821#endif
1822}
1823
1824HRESULT Host::findHostNetworkInterfacesOfType(HostNetworkInterfaceType_T aType,
1825 std::vector<ComPtr<IHostNetworkInterface> > &aNetworkInterfaces)
1826{
1827#ifdef VBOX_WITH_HOSTNETIF_API
1828 HRESULT hrc = i_updateNetIfList();
1829 if (FAILED(hrc))
1830 {
1831 Log(("Failed to update host network interface list with hrc=%Rhrc\n", hrc));
1832 return hrc;
1833 }
1834#if defined(RT_OS_WINDOWS)
1835 hrc = i_updatePersistentConfigForHostOnlyAdapters();
1836 if (FAILED(hrc))
1837 {
1838 LogRel(("Failed to update persistent config for host-only adapters with hrc=%Rhrc\n", hrc));
1839 return hrc;
1840 }
1841#endif /* defined(RT_OS_WINDOWS) */
1842
1843 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1844
1845 HostNetworkInterfaceList resultList;
1846 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1847 {
1848 HostNetworkInterfaceType_T t;
1849 hrc = (*it)->COMGETTER(InterfaceType)(&t);
1850 if (FAILED(hrc))
1851 return hrc;
1852
1853 if (t == aType)
1854 resultList.push_back(*it);
1855 }
1856 aNetworkInterfaces.resize(resultList.size());
1857 size_t i = 0;
1858 for (HostNetworkInterfaceList::iterator it = resultList.begin(); it != resultList.end(); ++it, ++i)
1859 {
1860 (*it).queryInterfaceTo(aNetworkInterfaces[i].asOutParam());
1861 }
1862
1863 return S_OK;
1864#else
1865 RT_NOREF(aType, aNetworkInterfaces);
1866 return E_NOTIMPL;
1867#endif
1868}
1869
1870HRESULT Host::findUSBDeviceByAddress(const com::Utf8Str &aName,
1871 ComPtr<IHostUSBDevice> &aDevice)
1872{
1873#ifdef VBOX_WITH_USB
1874
1875 aDevice = NULL;
1876 SafeIfaceArray<IHostUSBDevice> devsvec;
1877 HRESULT hrc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
1878 if (FAILED(hrc))
1879 return hrc;
1880
1881 for (size_t i = 0; i < devsvec.size(); ++i)
1882 {
1883 Bstr address;
1884 hrc = devsvec[i]->COMGETTER(Address)(address.asOutParam());
1885 if (FAILED(hrc))
1886 return hrc;
1887 if (address == aName)
1888 {
1889 return (ComPtr<IHostUSBDevice>(devsvec[i]).queryInterfaceTo(aDevice.asOutParam()));
1890 }
1891 }
1892
1893 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1894 tr("Could not find a USB device with address '%s'"),
1895 aName.c_str());
1896
1897#else /* !VBOX_WITH_USB */
1898 RT_NOREF(aName, aDevice);
1899 return E_NOTIMPL;
1900#endif /* !VBOX_WITH_USB */
1901}
1902HRESULT Host::findUSBDeviceById(const com::Guid &aId,
1903 ComPtr<IHostUSBDevice> &aDevice)
1904{
1905#ifdef VBOX_WITH_USB
1906 if (!aId.isValid())
1907 return E_INVALIDARG;
1908
1909 aDevice = NULL;
1910
1911 SafeIfaceArray<IHostUSBDevice> devsvec;
1912 HRESULT hrc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
1913 if (FAILED(hrc))
1914 return hrc;
1915
1916 for (size_t i = 0; i < devsvec.size(); ++i)
1917 {
1918 Bstr id;
1919 hrc = devsvec[i]->COMGETTER(Id)(id.asOutParam());
1920 if (FAILED(hrc))
1921 return hrc;
1922 if (Guid(id) == aId)
1923 {
1924 return (ComPtr<IHostUSBDevice>(devsvec[i]).queryInterfaceTo(aDevice.asOutParam()));
1925 }
1926 }
1927 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1928 tr("Could not find a USB device with uuid {%RTuuid}"),
1929 aId.raw());
1930
1931#else /* !VBOX_WITH_USB */
1932 RT_NOREF(aId, aDevice);
1933 return E_NOTIMPL;
1934#endif /* !VBOX_WITH_USB */
1935}
1936
1937HRESULT Host::generateMACAddress(com::Utf8Str &aAddress)
1938{
1939 // no locking required
1940 i_generateMACAddress(aAddress);
1941 return S_OK;
1942}
1943
1944/**
1945 * Returns a list of host video capture devices (webcams, etc).
1946 *
1947 * @returns COM status code
1948 * @param aVideoInputDevices Array of interface pointers to be filled.
1949 */
1950HRESULT Host::getVideoInputDevices(std::vector<ComPtr<IHostVideoInputDevice> > &aVideoInputDevices)
1951{
1952 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1953 HostVideoInputDeviceList list;
1954
1955 HRESULT hrc = HostVideoInputDevice::queryHostDevices(m->pParent, &list);
1956 if (FAILED(hrc))
1957 return hrc;
1958
1959 aVideoInputDevices.resize(list.size());
1960 size_t i = 0;
1961 for (HostVideoInputDeviceList::const_iterator it = list.begin(); it != list.end(); ++it, ++i)
1962 (*it).queryInterfaceTo(aVideoInputDevices[i].asOutParam());
1963
1964 return S_OK;
1965}
1966
1967/**
1968 * Returns the x86 host specific portions of the host object.
1969 *
1970 * @returns x86 host specific portions of the host object.
1971 * @param aHostX86 Where to return the x86 host specific portions of the host objects.
1972 */
1973HRESULT Host::getX86(ComPtr<IHostX86> &aHostX86)
1974{
1975 return m->pHostX86.queryInterfaceTo(aHostX86.asOutParam());
1976}
1977
1978HRESULT Host::addUSBDeviceSource(const com::Utf8Str &aBackend, const com::Utf8Str &aId, const com::Utf8Str &aAddress,
1979 const std::vector<com::Utf8Str> &aPropertyNames, const std::vector<com::Utf8Str> &aPropertyValues)
1980{
1981#ifdef VBOX_WITH_USB
1982 /* The USB proxy service will do the locking. */
1983 return m->pUSBProxyService->addUSBDeviceSource(aBackend, aId, aAddress, aPropertyNames, aPropertyValues);
1984#else
1985 RT_NOREF(aBackend, aId, aAddress, aPropertyNames, aPropertyValues);
1986 ReturnComNotImplemented();
1987#endif
1988}
1989
1990HRESULT Host::removeUSBDeviceSource(const com::Utf8Str &aId)
1991{
1992#ifdef VBOX_WITH_USB
1993 /* The USB proxy service will do the locking. */
1994 return m->pUSBProxyService->removeUSBDeviceSource(aId);
1995#else
1996 RT_NOREF(aId);
1997 ReturnComNotImplemented();
1998#endif
1999}
2000
2001HRESULT Host::getUpdateHost(ComPtr<IUpdateAgent> &aUpdate)
2002{
2003#ifdef VBOX_WITH_UPDATE_AGENT
2004 HRESULT hrc = m->pUpdateHost.queryInterfaceTo(aUpdate.asOutParam());
2005 return hrc;
2006#else
2007 RT_NOREF(aUpdate);
2008 ReturnComNotImplemented();
2009#endif
2010}
2011
2012HRESULT Host::getUpdateExtPack(ComPtr<IUpdateAgent> &aUpdate)
2013{
2014 RT_NOREF(aUpdate);
2015 ReturnComNotImplemented();
2016}
2017
2018HRESULT Host::getUpdateGuestAdditions(ComPtr<IUpdateAgent> &aUpdate)
2019{
2020 RT_NOREF(aUpdate);
2021 ReturnComNotImplemented();
2022}
2023
2024HRESULT Host::getHostDrives(std::vector<ComPtr<IHostDrive> > &aHostDrives)
2025{
2026 std::list<std::pair<com::Utf8Str, com::Utf8Str> > llDrivesPathsList;
2027 HRESULT hrc = i_getDrivesPathsList(llDrivesPathsList);
2028 if (SUCCEEDED(hrc))
2029 {
2030 for (std::list<std::pair<com::Utf8Str, com::Utf8Str> >::const_iterator it = llDrivesPathsList.begin();
2031 it != llDrivesPathsList.end();
2032 ++it)
2033 {
2034 ComObjPtr<HostDrive> pHostDrive;
2035 hrc = pHostDrive.createObject();
2036 if (SUCCEEDED(hrc))
2037 hrc = pHostDrive->initFromPathAndModel(it->first, it->second);
2038 if (FAILED(hrc))
2039 break;
2040 aHostDrives.push_back(pHostDrive);
2041 }
2042 }
2043 return hrc;
2044}
2045
2046
2047HRESULT Host::isExecutionEngineSupported(CPUArchitecture_T enmCpuArchitecture, VMExecutionEngine_T enmExecutionEngine, BOOL *pfIsSupported)
2048{
2049 *pfIsSupported = FALSE;
2050
2051 /* No need to lock anything as this is constant. */
2052 switch (enmCpuArchitecture)
2053 {
2054 case CPUArchitecture_x86:
2055 case CPUArchitecture_AMD64:
2056 {
2057 switch (enmExecutionEngine)
2058 {
2059 case VMExecutionEngine_Default:
2060 case VMExecutionEngine_Interpreter:
2061 *pfIsSupported = TRUE;
2062 break;
2063 case VMExecutionEngine_Recompiler:
2064#ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
2065 *pfIsSupported = TRUE;
2066#endif
2067 break;
2068#ifdef RT_ARCH_AMD64
2069# ifndef VBOX_WITH_DRIVERLESS_FORCED
2070 case VMExecutionEngine_HwVirt:
2071 *pfIsSupported = TRUE; /** @todo Check whether our driver is actually accessible?. */
2072 break;
2073# endif
2074# ifdef VBOX_WITH_NATIVE_NEM
2075 case VMExecutionEngine_NativeApi:
2076 *pfIsSupported = i_HostIsNativeApiSupported();
2077 break;
2078# endif
2079#endif
2080 default:
2081 break;
2082 }
2083 break;
2084 }
2085
2086 case CPUArchitecture_ARMv8_64:
2087 {
2088#ifdef VBOX_WITH_VIRT_ARMV8
2089 switch (enmExecutionEngine)
2090 {
2091#ifdef RT_ARCH_ARM64
2092# ifdef VBOX_WITH_NATIVE_NEM
2093 case VMExecutionEngine_NativeApi:
2094 *pfIsSupported = i_HostIsNativeApiSupported();
2095 break;
2096# endif
2097#endif
2098 default:
2099 break;
2100 }
2101#endif
2102 break;
2103 }
2104
2105 /* Not supported at all right now. */
2106 case CPUArchitecture_ARMv8_32:
2107 break;
2108
2109 default:
2110 AssertFailed();
2111 break;
2112 }
2113
2114 return S_OK;
2115}
2116
2117
2118// public methods only for internal purposes
2119////////////////////////////////////////////////////////////////////////////////
2120
2121HRESULT Host::i_loadSettings(const settings::Host &data)
2122{
2123 HRESULT hrc = S_OK;
2124#ifdef VBOX_WITH_USB
2125 AutoCaller autoCaller(this);
2126 if (FAILED(autoCaller.hrc()))
2127 return autoCaller.hrc();
2128
2129 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2130
2131 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
2132 it != data.llUSBDeviceFilters.end();
2133 ++it)
2134 {
2135 const settings::USBDeviceFilter &f = *it;
2136 ComObjPtr<HostUSBDeviceFilter> pFilter;
2137 pFilter.createObject();
2138 hrc = pFilter->init(this, f);
2139 if (FAILED(hrc))
2140 break;
2141
2142 m->llUSBDeviceFilters.push_back(pFilter);
2143 pFilter->mInList = true;
2144
2145 /* notify the proxy (only when the filter is active) */
2146 if (pFilter->i_getData().mData.fActive)
2147 {
2148 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
2149 flt->i_getId() = m->pUSBProxyService->insertFilter(&pFilter->i_getData().mUSBFilter);
2150 }
2151 }
2152
2153 hrc = m->pUSBProxyService->i_loadSettings(data.llUSBDeviceSources);
2154#else
2155 RT_NOREF(data);
2156#endif /* VBOX_WITH_USB */
2157
2158#ifdef VBOX_WITH_UPDATE_AGENT
2159 hrc = m->pUpdateHost->i_loadSettings(data.updateHost);
2160 ComAssertComRCRet(hrc, hrc);
2161 /** @todo Add handling for ExtPack and Guest Additions updates here later. See @bugref{7983}. */
2162#endif
2163
2164 return hrc;
2165}
2166
2167HRESULT Host::i_saveSettings(settings::Host &data)
2168{
2169 AutoCaller autoCaller(this);
2170 if (FAILED(autoCaller.hrc()))
2171 return autoCaller.hrc();
2172
2173 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2174
2175 HRESULT hrc;
2176
2177#ifdef VBOX_WITH_USB
2178 data.llUSBDeviceFilters.clear();
2179 data.llUSBDeviceSources.clear();
2180
2181 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
2182 it != m->llUSBDeviceFilters.end();
2183 ++it)
2184 {
2185 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
2186 settings::USBDeviceFilter f;
2187 pFilter->i_saveSettings(f);
2188 data.llUSBDeviceFilters.push_back(f);
2189 }
2190
2191 hrc = m->pUSBProxyService->i_saveSettings(data.llUSBDeviceSources);
2192 ComAssertComRCRet(hrc, hrc);
2193#else
2194 RT_NOREF(data);
2195#endif /* VBOX_WITH_USB */
2196
2197#ifdef VBOX_WITH_UPDATE_AGENT
2198 hrc = m->pUpdateHost->i_saveSettings(data.updateHost);
2199 ComAssertComRCRet(hrc, hrc);
2200 /** @todo Add handling for ExtPack and Guest Additions updates here later. See @bugref{7983}. */
2201#endif
2202
2203 return S_OK;
2204}
2205
2206/**
2207 * Sets the given pointer to point to the static list of DVD or floppy
2208 * drives in the Host instance data, depending on the @a mediumType
2209 * parameter.
2210 *
2211 * This builds the list on the first call; it adds or removes host drives
2212 * that may have changed if fRefresh == true.
2213 *
2214 * The caller must hold the medium tree write lock before calling this.
2215 * To protect the list to which the caller's pointer points, the caller
2216 * must also hold that lock.
2217 *
2218 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
2219 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
2220 * @param pll Caller's pointer which gets set to the static list of host drives.
2221 * @param treeLock Reference to media tree lock, need to drop it temporarily.
2222 * @returns COM status code
2223 */
2224HRESULT Host::i_getDrives(DeviceType_T mediumType,
2225 bool fRefresh,
2226 MediaList *&pll,
2227 AutoWriteLock &treeLock)
2228{
2229 HRESULT hrc = S_OK;
2230 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2231
2232 MediaList llNew;
2233 MediaList *pllCached;
2234 bool *pfListBuilt = NULL;
2235
2236 switch (mediumType)
2237 {
2238 case DeviceType_DVD:
2239 if (!m->fDVDDrivesListBuilt || fRefresh)
2240 {
2241 hrc = i_buildDVDDrivesList(llNew);
2242 if (FAILED(hrc))
2243 return hrc;
2244 pfListBuilt = &m->fDVDDrivesListBuilt;
2245 }
2246 pllCached = &m->llDVDDrives;
2247 break;
2248
2249 case DeviceType_Floppy:
2250 if (!m->fFloppyDrivesListBuilt || fRefresh)
2251 {
2252 hrc = i_buildFloppyDrivesList(llNew);
2253 if (FAILED(hrc))
2254 return hrc;
2255 pfListBuilt = &m->fFloppyDrivesListBuilt;
2256 }
2257 pllCached = &m->llFloppyDrives;
2258 break;
2259
2260 default:
2261 return E_INVALIDARG;
2262 }
2263
2264 if (pfListBuilt)
2265 {
2266 // a list was built in llNew above:
2267 if (!*pfListBuilt)
2268 {
2269 // this was the first call (instance bool is still false): then just copy the whole list and return
2270 *pllCached = llNew;
2271 // and mark the instance data as "built"
2272 *pfListBuilt = true;
2273 }
2274 else
2275 {
2276 // list was built, and this was a subsequent call: then compare the old and the new lists
2277
2278 // remove drives from the cached list which are no longer present
2279 for (MediaList::iterator itCached = pllCached->begin();
2280 itCached != pllCached->end();
2281 /*nothing */)
2282 {
2283 Medium *pCached = *itCached;
2284 const Utf8Str strLocationCached = pCached->i_getLocationFull();
2285 bool fFound = false;
2286 for (MediaList::iterator itNew = llNew.begin();
2287 itNew != llNew.end();
2288 ++itNew)
2289 {
2290 Medium *pNew = *itNew;
2291 const Utf8Str strLocationNew = pNew->i_getLocationFull();
2292 if (strLocationNew == strLocationCached)
2293 {
2294 fFound = true;
2295 break;
2296 }
2297 }
2298 if (!fFound)
2299 {
2300 pCached->uninit();
2301 itCached = pllCached->erase(itCached);
2302 }
2303 else
2304 ++itCached;
2305 }
2306
2307 // add drives to the cached list that are not on there yet
2308 for (MediaList::iterator itNew = llNew.begin();
2309 itNew != llNew.end();
2310 ++itNew)
2311 {
2312 Medium *pNew = *itNew;
2313 const Utf8Str strLocationNew = pNew->i_getLocationFull();
2314 bool fFound = false;
2315 for (MediaList::iterator itCached = pllCached->begin();
2316 itCached != pllCached->end();
2317 ++itCached)
2318 {
2319 Medium *pCached = *itCached;
2320 const Utf8Str strLocationCached = pCached->i_getLocationFull();
2321 if (strLocationNew == strLocationCached)
2322 {
2323 fFound = true;
2324 break;
2325 }
2326 }
2327
2328 if (!fFound)
2329 pllCached->push_back(pNew);
2330 }
2331 }
2332 }
2333
2334 // return cached list to caller
2335 pll = pllCached;
2336
2337 // Make sure the media tree lock is released before llNew is cleared,
2338 // as this usually triggers calls to uninit().
2339 treeLock.release();
2340
2341 llNew.clear();
2342
2343 treeLock.acquire();
2344
2345 return hrc;
2346}
2347
2348/**
2349 * Goes through the list of host drives that would be returned by getDrives()
2350 * and looks for a host drive with the given UUID. If found, it sets pMedium
2351 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2352 *
2353 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2354 * @param uuid Medium UUID of host drive to look for.
2355 * @param fRefresh Whether to refresh the host drives list (see getDrives())
2356 * @param pMedium Medium object, if found...
2357 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2358 */
2359HRESULT Host::i_findHostDriveById(DeviceType_T mediumType,
2360 const Guid &uuid,
2361 bool fRefresh,
2362 ComObjPtr<Medium> &pMedium)
2363{
2364 MediaList *pllMedia;
2365
2366 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2367 HRESULT hrc = i_getDrives(mediumType, fRefresh, pllMedia, treeLock);
2368 if (SUCCEEDED(hrc))
2369 {
2370 for (MediaList::iterator it = pllMedia->begin();
2371 it != pllMedia->end();
2372 ++it)
2373 {
2374 Medium *pThis = *it;
2375 AutoCaller mediumCaller(pThis);
2376 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
2377 if (pThis->i_getId() == uuid)
2378 {
2379 pMedium = pThis;
2380 return S_OK;
2381 }
2382 }
2383 }
2384
2385 return VBOX_E_OBJECT_NOT_FOUND;
2386}
2387
2388/**
2389 * Goes through the list of host drives that would be returned by getDrives()
2390 * and looks for a host drive with the given name. If found, it sets pMedium
2391 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2392 *
2393 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2394 * @param strLocationFull Name (path) of host drive to look for.
2395 * @param fRefresh Whether to refresh the host drives list (see getDrives())
2396 * @param pMedium Medium object, if found
2397 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2398 */
2399HRESULT Host::i_findHostDriveByName(DeviceType_T mediumType,
2400 const Utf8Str &strLocationFull,
2401 bool fRefresh,
2402 ComObjPtr<Medium> &pMedium)
2403{
2404 MediaList *pllMedia;
2405
2406 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2407 HRESULT hrc = i_getDrives(mediumType, fRefresh, pllMedia, treeLock);
2408 if (SUCCEEDED(hrc))
2409 {
2410 for (MediaList::iterator it = pllMedia->begin();
2411 it != pllMedia->end();
2412 ++it)
2413 {
2414 Medium *pThis = *it;
2415 AutoCaller mediumCaller(pThis);
2416 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
2417 if (pThis->i_getLocationFull() == strLocationFull)
2418 {
2419 pMedium = pThis;
2420 return S_OK;
2421 }
2422 }
2423 }
2424
2425 return VBOX_E_OBJECT_NOT_FOUND;
2426}
2427
2428/**
2429 * Goes through the list of host drives that would be returned by getDrives()
2430 * and looks for a host drive with the given name, location or ID. If found,
2431 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2432 *
2433 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2434 * @param strNameOrId Name or full location or UUID of host drive to look for.
2435 * @param pMedium Medium object, if found...
2436 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2437 */
2438HRESULT Host::i_findHostDriveByNameOrId(DeviceType_T mediumType,
2439 const Utf8Str &strNameOrId,
2440 ComObjPtr<Medium> &pMedium)
2441{
2442 AutoWriteLock wlock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2443
2444 Guid uuid(strNameOrId);
2445 if (uuid.isValid() && !uuid.isZero())
2446 return i_findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
2447
2448 // string is not a syntactically valid UUID: try a name then
2449 return i_findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
2450}
2451
2452/**
2453 * Called from getDrives() to build the DVD drives list.
2454 * @param list Media list
2455 * @return
2456 */
2457HRESULT Host::i_buildDVDDrivesList(MediaList &list)
2458{
2459 HRESULT hrc = S_OK;
2460
2461 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2462
2463 try
2464 {
2465#if defined(RT_OS_WINDOWS)
2466 int sz = GetLogicalDriveStrings(0, NULL);
2467 TCHAR *hostDrives = new TCHAR[sz+1];
2468 GetLogicalDriveStrings(sz, hostDrives);
2469 wchar_t driveName[3] = { '?', ':', '\0' };
2470 TCHAR *p = hostDrives;
2471 do
2472 {
2473 if (GetDriveType(p) == DRIVE_CDROM)
2474 {
2475 driveName[0] = *p;
2476 ComObjPtr<Medium> hostDVDDriveObj;
2477 hostDVDDriveObj.createObject();
2478 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
2479 list.push_back(hostDVDDriveObj);
2480 }
2481 p += _tcslen(p) + 1;
2482 }
2483 while (*p);
2484 delete[] hostDrives;
2485
2486#elif defined(RT_OS_SOLARIS)
2487# ifdef VBOX_USE_LIBHAL
2488 if (!i_getDVDInfoFromHal(list))
2489# endif
2490 {
2491 i_getDVDInfoFromDevTree(list);
2492 }
2493
2494#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
2495 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
2496 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
2497 SUCCEEDED(hrc) && it != m->hostDrives.DVDEnd(); ++it)
2498 {
2499 ComObjPtr<Medium> hostDVDDriveObj;
2500 Utf8Str location(it->mDevice);
2501 Utf8Str description(it->mDescription);
2502 if (SUCCEEDED(hrc))
2503 hrc = hostDVDDriveObj.createObject();
2504 if (SUCCEEDED(hrc))
2505 hrc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
2506 if (SUCCEEDED(hrc))
2507 list.push_back(hostDVDDriveObj);
2508 }
2509#elif defined(RT_OS_DARWIN)
2510 PDARWINDVD cur = DarwinGetDVDDrives();
2511 while (cur)
2512 {
2513 ComObjPtr<Medium> hostDVDDriveObj;
2514 hostDVDDriveObj.createObject();
2515 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
2516 list.push_back(hostDVDDriveObj);
2517
2518 /* next */
2519 void *freeMe = cur;
2520 cur = cur->pNext;
2521 RTMemFree(freeMe);
2522 }
2523#else
2524 /* PORTME */
2525#endif
2526 }
2527 catch (std::bad_alloc &)
2528 {
2529 hrc = E_OUTOFMEMORY;
2530 }
2531 return hrc;
2532}
2533
2534/**
2535 * Called from getDrives() to build the floppy drives list.
2536 * @param list
2537 * @return
2538 */
2539HRESULT Host::i_buildFloppyDrivesList(MediaList &list)
2540{
2541 HRESULT hrc = S_OK;
2542
2543 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2544
2545 try
2546 {
2547#ifdef RT_OS_WINDOWS
2548 int sz = GetLogicalDriveStrings(0, NULL);
2549 TCHAR *hostDrives = new TCHAR[sz+1];
2550 GetLogicalDriveStrings(sz, hostDrives);
2551 wchar_t driveName[3] = { '?', ':', '\0' };
2552 TCHAR *p = hostDrives;
2553 do
2554 {
2555 if (GetDriveType(p) == DRIVE_REMOVABLE)
2556 {
2557 driveName[0] = *p;
2558 ComObjPtr<Medium> hostFloppyDriveObj;
2559 hostFloppyDriveObj.createObject();
2560 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
2561 list.push_back(hostFloppyDriveObj);
2562 }
2563 p += _tcslen(p) + 1;
2564 }
2565 while (*p);
2566 delete[] hostDrives;
2567#elif defined(RT_OS_LINUX)
2568 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
2569 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
2570 SUCCEEDED(hrc) && it != m->hostDrives.FloppyEnd(); ++it)
2571 {
2572 ComObjPtr<Medium> hostFloppyDriveObj;
2573 Utf8Str location(it->mDevice);
2574 Utf8Str description(it->mDescription);
2575 if (SUCCEEDED(hrc))
2576 hrc = hostFloppyDriveObj.createObject();
2577 if (SUCCEEDED(hrc))
2578 hrc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
2579 if (SUCCEEDED(hrc))
2580 list.push_back(hostFloppyDriveObj);
2581 }
2582#else
2583 RT_NOREF(list);
2584 /* PORTME */
2585#endif
2586 }
2587 catch(std::bad_alloc &)
2588 {
2589 hrc = E_OUTOFMEMORY;
2590 }
2591
2592 return hrc;
2593}
2594
2595#ifdef VBOX_WITH_USB
2596USBProxyService* Host::i_usbProxyService()
2597{
2598 return m->pUSBProxyService;
2599}
2600
2601HRESULT Host::i_addChild(HostUSBDeviceFilter *pChild)
2602{
2603 AutoCaller autoCaller(this);
2604 if (FAILED(autoCaller.hrc()))
2605 return autoCaller.hrc();
2606
2607 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2608
2609 m->llChildren.push_back(pChild);
2610
2611 return S_OK;
2612}
2613
2614HRESULT Host::i_removeChild(HostUSBDeviceFilter *pChild)
2615{
2616 AutoCaller autoCaller(this);
2617 if (FAILED(autoCaller.hrc()))
2618 return autoCaller.hrc();
2619
2620 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2621
2622 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
2623 it != m->llChildren.end();
2624 ++it)
2625 {
2626 if (*it == pChild)
2627 {
2628 m->llChildren.erase(it);
2629 break;
2630 }
2631 }
2632
2633 return S_OK;
2634}
2635
2636VirtualBox* Host::i_parent()
2637{
2638 return m->pParent;
2639}
2640
2641/**
2642 * Called by setter methods of all USB device filters.
2643 */
2644HRESULT Host::i_onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2645 BOOL aActiveChanged /* = FALSE */)
2646{
2647 AutoCaller autoCaller(this);
2648 if (FAILED(autoCaller.hrc()))
2649 return autoCaller.hrc();
2650
2651 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2652
2653 if (aFilter->mInList)
2654 {
2655 if (aActiveChanged)
2656 {
2657 // insert/remove the filter from the proxy
2658 if (aFilter->i_getData().mData.fActive)
2659 {
2660 ComAssertRet(aFilter->i_getId() == NULL, E_FAIL);
2661 aFilter->i_getId() = m->pUSBProxyService->insertFilter(&aFilter->i_getData().mUSBFilter);
2662 }
2663 else
2664 {
2665 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
2666 m->pUSBProxyService->removeFilter(aFilter->i_getId());
2667 aFilter->i_getId() = NULL;
2668 }
2669 }
2670 else
2671 {
2672 if (aFilter->i_getData().mData.fActive)
2673 {
2674 // update the filter in the proxy
2675 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
2676 m->pUSBProxyService->removeFilter(aFilter->i_getId());
2677 aFilter->i_getId() = m->pUSBProxyService->insertFilter(&aFilter->i_getData().mUSBFilter);
2678 }
2679 }
2680
2681 // save the global settings... yeah, on every single filter property change
2682 // for that we should hold only the VirtualBox lock
2683 alock.release();
2684 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2685 return m->pParent->i_saveSettings();
2686 }
2687
2688 return S_OK;
2689}
2690
2691
2692/**
2693 * Interface for obtaining a copy of the USBDeviceFilterList,
2694 * used by the USBProxyService.
2695 *
2696 * @param aGlobalFilters Where to put the global filter list copy.
2697 * @param aMachines Where to put the machine vector.
2698 */
2699void Host::i_getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2700{
2701 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2702
2703 *aGlobalFilters = m->llUSBDeviceFilters;
2704}
2705
2706#endif /* VBOX_WITH_USB */
2707
2708// private methods
2709////////////////////////////////////////////////////////////////////////////////
2710
2711#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2712
2713/**
2714 * Helper function to get the slice number from a device path
2715 *
2716 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2717 * @returns Pointer to the slice portion of the given path.
2718 */
2719static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2720{
2721 char *pszSlice = (char *)strrchr(pszDevLinkPath, 's');
2722 char *pszDisk = (char *)strrchr(pszDevLinkPath, 'd');
2723 char *pszFound;
2724 if (pszSlice && (uintptr_t)pszSlice > (uintptr_t)pszDisk)
2725 pszFound = pszSlice;
2726 else
2727 pszFound = pszDisk;
2728
2729 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2730 return pszFound;
2731
2732 return NULL;
2733}
2734
2735/**
2736 * Walk device links and returns an allocated path for the first one in the snapshot.
2737 *
2738 * @param DevLink Handle to the device link being walked.
2739 * @param pvArg Opaque pointer that we use to point to the return
2740 * variable (char *). Caller must call RTStrFree on it.
2741 * @returns DI_WALK_TERMINATE to stop the walk.
2742 */
2743static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2744{
2745 char **ppszPath = (char **)pvArg;
2746 *ppszPath = RTStrDup(di_devlink_path(DevLink));
2747 return DI_WALK_TERMINATE;
2748}
2749
2750/**
2751 * Walk all devices in the system and enumerate CD/DVD drives.
2752 * @param Node Handle to the current node.
2753 * @param pvArg Opaque data (holds list pointer).
2754 * @returns Solaris specific code whether to continue walking or not.
2755 */
2756static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2757{
2758 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2759
2760 /*
2761 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2762 * As unfortunately the Solaris drivers only export these common properties.
2763 */
2764 int *pInt = NULL;
2765 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2766 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2767 {
2768 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2769 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2770 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2771 {
2772 char *pszProduct = NULL;
2773 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2774 {
2775 char *pszVendor = NULL;
2776 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2777 {
2778 /*
2779 * Found a DVD drive, we need to scan the minor nodes to find the correct
2780 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2781 */
2782 int Major = di_driver_major(Node);
2783 di_minor_t Minor = DI_MINOR_NIL;
2784 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2785 if (DevLink)
2786 {
2787 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2788 {
2789 dev_t Dev = di_minor_devt(Minor);
2790 if ( Major != (int)major(Dev)
2791 || di_minor_spectype(Minor) == S_IFBLK
2792 || di_minor_type(Minor) != DDM_MINOR)
2793 {
2794 continue;
2795 }
2796
2797 char *pszMinorPath = di_devfs_minor_path(Minor);
2798 if (!pszMinorPath)
2799 continue;
2800
2801 char *pszDevLinkPath = NULL;
2802 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2803 di_devfs_path_free(pszMinorPath);
2804
2805 if (pszDevLinkPath)
2806 {
2807 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2808 if ( pszSlice && !strcmp(pszSlice, "s2")
2809 && !strncmp(pszDevLinkPath, RT_STR_TUPLE("/dev/rdsk"))) /* We want only raw disks */
2810 {
2811 /*
2812 * We've got a fully qualified DVD drive. Add it to the list.
2813 */
2814 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2815 if (RT_LIKELY(pDrive))
2816 {
2817 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription),
2818 "%s %s", pszVendor, pszProduct);
2819 RTStrPurgeEncoding(pDrive->szDescription);
2820 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2821 if (*ppDrives)
2822 pDrive->pNext = *ppDrives;
2823 *ppDrives = pDrive;
2824
2825 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2826 RTStrFree(pszDevLinkPath);
2827 break;
2828 }
2829 }
2830 RTStrFree(pszDevLinkPath);
2831 }
2832 }
2833 di_devlink_fini(&DevLink);
2834 }
2835 }
2836 }
2837 }
2838 }
2839 return DI_WALK_CONTINUE;
2840}
2841
2842/**
2843 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2844 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2845 */
2846void Host::i_getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2847{
2848 PSOLARISDVD pDrives = NULL;
2849 di_node_t RootNode = di_init("/", DINFOCPYALL);
2850 if (RootNode != DI_NODE_NIL)
2851 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2852
2853 di_fini(RootNode);
2854
2855 while (pDrives)
2856 {
2857 ComObjPtr<Medium> hostDVDDriveObj;
2858 hostDVDDriveObj.createObject();
2859 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2860 list.push_back(hostDVDDriveObj);
2861
2862 void *pvDrive = pDrives;
2863 pDrives = pDrives->pNext;
2864 RTMemFree(pvDrive);
2865 }
2866}
2867
2868
2869/**
2870 * Walk all devices in the system and enumerate fixed drives.
2871 * @param Node Handle to the current node.
2872 * @param pvArg Opaque data (holds list pointer).
2873 * @returns Solaris specific code whether to continue walking or not.
2874 */
2875static int solarisWalkDeviceNodeForFixedDrive(di_node_t Node, void *pvArg) RT_NOEXCEPT
2876{
2877 PSOLARISFIXEDDISK *ppDrives = (PSOLARISFIXEDDISK *)pvArg;
2878
2879 int *pInt = NULL;
2880 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2881 && *pInt == DTYPE_DIRECT) /* Fixed drive */
2882 {
2883 char *pszProduct = NULL;
2884 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2885 {
2886 char *pszVendor = NULL;
2887 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2888 {
2889 /*
2890 * Found a fixed drive, we need to scan the minor nodes to find the correct
2891 * slice that represents the whole drive.
2892 */
2893 int Major = di_driver_major(Node);
2894 di_minor_t Minor = DI_MINOR_NIL;
2895 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2896 if (DevLink)
2897 {
2898 /*
2899 * The device name we have to select depends on drive type. For fixed drives, the
2900 * name without slice or partition should be selected, for USB flash drive the
2901 * partition 0 should be selected and slice 0 for other cases.
2902 */
2903 char *pszDisk = NULL;
2904 char *pszPartition0 = NULL;
2905 char *pszSlice0 = NULL;
2906 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2907 {
2908 dev_t Dev = di_minor_devt(Minor);
2909 if ( Major != (int)major(Dev)
2910 || di_minor_spectype(Minor) == S_IFBLK
2911 || di_minor_type(Minor) != DDM_MINOR)
2912 continue;
2913
2914 char *pszMinorPath = di_devfs_minor_path(Minor);
2915 if (!pszMinorPath)
2916 continue;
2917
2918 char *pszDevLinkPath = NULL;
2919 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2920 di_devfs_path_free(pszMinorPath);
2921
2922 if (pszDevLinkPath)
2923 {
2924 char const *pszCurSlice = strrchr(pszDevLinkPath, 's');
2925 char const *pszCurDisk = strrchr(pszDevLinkPath, 'd');
2926 char const *pszCurPart = strrchr(pszDevLinkPath, 'p');
2927 char **ppszDst = NULL;
2928 if (pszCurSlice && (uintptr_t)pszCurSlice > (uintptr_t)pszCurDisk && !strcmp(pszCurSlice, "s0"))
2929 ppszDst = &pszSlice0;
2930 else if (pszCurPart && (uintptr_t)pszCurPart > (uintptr_t)pszCurDisk && !strcmp(pszCurPart, "p0"))
2931 ppszDst = &pszPartition0;
2932 else if ( (!pszCurSlice || (uintptr_t)pszCurSlice < (uintptr_t)pszCurDisk)
2933 && (!pszCurPart || (uintptr_t)pszCurPart < (uintptr_t)pszCurDisk)
2934 && *pszDevLinkPath != '\0')
2935 ppszDst = &pszDisk;
2936 else
2937 RTStrFree(pszDevLinkPath);
2938 if (ppszDst)
2939 {
2940 if (*ppszDst != NULL)
2941 RTStrFree(*ppszDst);
2942 *ppszDst = pszDevLinkPath;
2943 }
2944 }
2945 }
2946 di_devlink_fini(&DevLink);
2947 if (pszDisk || pszPartition0 || pszSlice0)
2948 {
2949 PSOLARISFIXEDDISK pDrive = (PSOLARISFIXEDDISK)RTMemAllocZ(sizeof(*pDrive));
2950 if (RT_LIKELY(pDrive))
2951 {
2952 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2953 RTStrPurgeEncoding(pDrive->szDescription);
2954
2955 const char *pszDevPath = pszDisk ? pszDisk : pszPartition0 ? pszPartition0 : pszSlice0;
2956 int vrc = RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevPath);
2957 AssertRC(vrc);
2958
2959 if (*ppDrives)
2960 pDrive->pNext = *ppDrives;
2961 *ppDrives = pDrive;
2962 }
2963 RTStrFree(pszDisk);
2964 RTStrFree(pszPartition0);
2965 RTStrFree(pszSlice0);
2966 }
2967 }
2968 }
2969 }
2970 }
2971 return DI_WALK_CONTINUE;
2972}
2973
2974
2975/**
2976 * Solaris specific function to enumerate fixed drives via the device tree.
2977 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2978 *
2979 * @returns COM status, either S_OK or E_OUTOFMEMORY.
2980 * @param list Reference to list where the the path/model pairs are to
2981 * be returned.
2982 */
2983HRESULT Host::i_getFixedDrivesFromDevTree(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &list) RT_NOEXCEPT
2984{
2985 PSOLARISFIXEDDISK pDrives = NULL;
2986 di_node_t RootNode = di_init("/", DINFOCPYALL);
2987 if (RootNode != DI_NODE_NIL)
2988 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForFixedDrive);
2989 di_fini(RootNode);
2990
2991 HRESULT hrc = S_OK;
2992 try
2993 {
2994 for (PSOLARISFIXEDDISK pCurDrv = pDrives; pCurDrv; pCurDrv = pCurDrv->pNext)
2995 list.push_back(std::pair<com::Utf8Str, com::Utf8Str>(pCurDrv->szRawDiskPath, pCurDrv->szDescription));
2996 }
2997 catch (std::bad_alloc &)
2998 {
2999 LogRelFunc(("Out of memory!\n"));
3000 list.clear();
3001 hrc = E_OUTOFMEMORY;
3002 }
3003
3004 while (pDrives)
3005 {
3006 PSOLARISFIXEDDISK pFreeMe = pDrives;
3007 pDrives = pDrives->pNext;
3008 ASMCompilerBarrier();
3009 RTMemFree(pFreeMe);
3010 }
3011
3012 return hrc;
3013}
3014
3015
3016/* Solaris hosts, loading libhal at runtime */
3017
3018/**
3019 * Helper function to query the hal subsystem for information about DVD drives attached to the
3020 * system.
3021 *
3022 * @returns true if information was successfully obtained, false otherwise
3023 * @param list Reference to list where the DVDs drives are to be returned.
3024 */
3025bool Host::i_getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
3026{
3027 bool halSuccess = false;
3028 DBusError dbusError;
3029 if (!gLibHalCheckPresence())
3030 return false;
3031 gDBusErrorInit(&dbusError);
3032 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
3033 if (dbusConnection != 0)
3034 {
3035 LibHalContext *halContext = gLibHalCtxNew();
3036 if (halContext != 0)
3037 {
3038 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
3039 {
3040 if (gLibHalCtxInit(halContext, &dbusError))
3041 {
3042 int numDevices;
3043 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
3044 "storage.drive_type", "cdrom",
3045 &numDevices, &dbusError);
3046 if (halDevices != 0)
3047 {
3048 /* Hal is installed and working, so if no devices are reported, assume
3049 that there are none. */
3050 halSuccess = true;
3051 for (int i = 0; i < numDevices; i++)
3052 {
3053 char *devNode = gLibHalDeviceGetPropertyString(halContext,
3054 halDevices[i], "block.device", &dbusError);
3055#ifdef RT_OS_SOLARIS
3056 /* The CD/DVD ioctls work only for raw device nodes. */
3057 char *tmp = getfullrawname(devNode);
3058 gLibHalFreeString(devNode);
3059 devNode = tmp;
3060#endif
3061
3062 if (devNode != 0)
3063 {
3064// if (validateDevice(devNode, true))
3065// {
3066 Utf8Str description;
3067 char *vendor, *product;
3068 /* We do not check the error here, as this field may
3069 not even exist. */
3070 vendor = gLibHalDeviceGetPropertyString(halContext,
3071 halDevices[i], "info.vendor", 0);
3072 product = gLibHalDeviceGetPropertyString(halContext,
3073 halDevices[i], "info.product", &dbusError);
3074 if ((product != 0 && product[0] != 0))
3075 {
3076 if ((vendor != 0) && (vendor[0] != 0))
3077 {
3078 description = Utf8StrFmt("%s %s",
3079 vendor, product);
3080 }
3081 else
3082 {
3083 description = product;
3084 }
3085 ComObjPtr<Medium> hostDVDDriveObj;
3086 hostDVDDriveObj.createObject();
3087 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
3088 Bstr(devNode), Bstr(description));
3089 list.push_back(hostDVDDriveObj);
3090 }
3091 else
3092 {
3093 if (product == 0)
3094 {
3095 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
3096 halDevices[i], dbusError.name, dbusError.message));
3097 gDBusErrorFree(&dbusError);
3098 }
3099 ComObjPtr<Medium> hostDVDDriveObj;
3100 hostDVDDriveObj.createObject();
3101 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
3102 Bstr(devNode));
3103 list.push_back(hostDVDDriveObj);
3104 }
3105 if (vendor != 0)
3106 {
3107 gLibHalFreeString(vendor);
3108 }
3109 if (product != 0)
3110 {
3111 gLibHalFreeString(product);
3112 }
3113// }
3114// else
3115// {
3116// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
3117// }
3118#ifndef RT_OS_SOLARIS
3119 gLibHalFreeString(devNode);
3120#else
3121 free(devNode);
3122#endif
3123 }
3124 else
3125 {
3126 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
3127 halDevices[i], dbusError.name, dbusError.message));
3128 gDBusErrorFree(&dbusError);
3129 }
3130 }
3131 gLibHalFreeStringArray(halDevices);
3132 }
3133 else
3134 {
3135 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
3136 gDBusErrorFree(&dbusError);
3137 }
3138 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
3139 {
3140 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
3141 dbusError.name, dbusError.message));
3142 gDBusErrorFree(&dbusError);
3143 }
3144 }
3145 else
3146 {
3147 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
3148 dbusError.name, dbusError.message));
3149 gDBusErrorFree(&dbusError);
3150 }
3151 gLibHalCtxFree(halContext);
3152 }
3153 else
3154 {
3155 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
3156 }
3157 }
3158 else
3159 {
3160 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
3161 }
3162 gDBusConnectionUnref(dbusConnection);
3163 }
3164 else
3165 {
3166 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3167 dbusError.name, dbusError.message));
3168 gDBusErrorFree(&dbusError);
3169 }
3170 return halSuccess;
3171}
3172
3173
3174/**
3175 * Helper function to query the hal subsystem for information about floppy drives attached to the
3176 * system.
3177 *
3178 * @returns true if information was successfully obtained, false otherwise
3179 * @retval list drives found will be attached to this list
3180 */
3181bool Host::i_getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
3182{
3183 bool halSuccess = false;
3184 DBusError dbusError;
3185 if (!gLibHalCheckPresence())
3186 return false;
3187 gDBusErrorInit(&dbusError);
3188 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
3189 if (dbusConnection != 0)
3190 {
3191 LibHalContext *halContext = gLibHalCtxNew();
3192 if (halContext != 0)
3193 {
3194 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
3195 {
3196 if (gLibHalCtxInit(halContext, &dbusError))
3197 {
3198 int numDevices;
3199 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
3200 "storage.drive_type", "floppy",
3201 &numDevices, &dbusError);
3202 if (halDevices != 0)
3203 {
3204 /* Hal is installed and working, so if no devices are reported, assume
3205 that there are none. */
3206 halSuccess = true;
3207 for (int i = 0; i < numDevices; i++)
3208 {
3209 char *driveType = gLibHalDeviceGetPropertyString(halContext,
3210 halDevices[i], "storage.drive_type", 0);
3211 if (driveType != 0)
3212 {
3213 if (strcmp(driveType, "floppy") != 0)
3214 {
3215 gLibHalFreeString(driveType);
3216 continue;
3217 }
3218 gLibHalFreeString(driveType);
3219 }
3220 else
3221 {
3222 /* An error occurred. The attribute "storage.drive_type"
3223 probably didn't exist. */
3224 continue;
3225 }
3226 char *devNode = gLibHalDeviceGetPropertyString(halContext,
3227 halDevices[i], "block.device", &dbusError);
3228 if (devNode != 0)
3229 {
3230// if (validateDevice(devNode, false))
3231// {
3232 Utf8Str description;
3233 char *vendor, *product;
3234 /* We do not check the error here, as this field may
3235 not even exist. */
3236 vendor = gLibHalDeviceGetPropertyString(halContext,
3237 halDevices[i], "info.vendor", 0);
3238 product = gLibHalDeviceGetPropertyString(halContext,
3239 halDevices[i], "info.product", &dbusError);
3240 if ((product != 0) && (product[0] != 0))
3241 {
3242 if ((vendor != 0) && (vendor[0] != 0))
3243 {
3244 description = Utf8StrFmt("%s %s",
3245 vendor, product);
3246 }
3247 else
3248 {
3249 description = product;
3250 }
3251 ComObjPtr<Medium> hostFloppyDrive;
3252 hostFloppyDrive.createObject();
3253 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
3254 Bstr(devNode), Bstr(description));
3255 list.push_back(hostFloppyDrive);
3256 }
3257 else
3258 {
3259 if (product == 0)
3260 {
3261 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
3262 halDevices[i], dbusError.name, dbusError.message));
3263 gDBusErrorFree(&dbusError);
3264 }
3265 ComObjPtr<Medium> hostFloppyDrive;
3266 hostFloppyDrive.createObject();
3267 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
3268 Bstr(devNode));
3269 list.push_back(hostFloppyDrive);
3270 }
3271 if (vendor != 0)
3272 {
3273 gLibHalFreeString(vendor);
3274 }
3275 if (product != 0)
3276 {
3277 gLibHalFreeString(product);
3278 }
3279// }
3280// else
3281// {
3282// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
3283// }
3284 gLibHalFreeString(devNode);
3285 }
3286 else
3287 {
3288 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
3289 halDevices[i], dbusError.name, dbusError.message));
3290 gDBusErrorFree(&dbusError);
3291 }
3292 }
3293 gLibHalFreeStringArray(halDevices);
3294 }
3295 else
3296 {
3297 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
3298 gDBusErrorFree(&dbusError);
3299 }
3300 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
3301 {
3302 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
3303 dbusError.name, dbusError.message));
3304 gDBusErrorFree(&dbusError);
3305 }
3306 }
3307 else
3308 {
3309 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
3310 dbusError.name, dbusError.message));
3311 gDBusErrorFree(&dbusError);
3312 }
3313 gLibHalCtxFree(halContext);
3314 }
3315 else
3316 {
3317 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
3318 }
3319 }
3320 else
3321 {
3322 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
3323 }
3324 gDBusConnectionUnref(dbusConnection);
3325 }
3326 else
3327 {
3328 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3329 dbusError.name, dbusError.message));
3330 gDBusErrorFree(&dbusError);
3331 }
3332 return halSuccess;
3333}
3334
3335
3336/**
3337 * Helper function to query the hal subsystem for information about fixed drives attached to the
3338 * system.
3339 *
3340 * @returns COM status code. (setError is not called on failure as we only fail
3341 * with E_OUTOFMEMORY.)
3342 * @retval S_OK on success.
3343 * @retval S_FALSE if HAL cannot be used.
3344 * @param list Reference to list to return the path/model string pairs.
3345 */
3346HRESULT Host::i_getFixedDrivesFromHal(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &list) RT_NOEXCEPT
3347{
3348 HRESULT hrc = S_FALSE;
3349 if (!gLibHalCheckPresence())
3350 return hrc;
3351
3352 DBusError dbusError;
3353 gDBusErrorInit(&dbusError);
3354 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
3355 if (dbusConnection != 0)
3356 {
3357 LibHalContext *halContext = gLibHalCtxNew();
3358 if (halContext != 0)
3359 {
3360 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
3361 {
3362 if (gLibHalCtxInit(halContext, &dbusError))
3363 {
3364 int cDevices;
3365 char **halDevices = gLibHalFindDeviceStringMatch(halContext, "storage.drive_type", "disk",
3366 &cDevices, &dbusError);
3367 if (halDevices != 0)
3368 {
3369 /* Hal is installed and working, so if no devices are reported, assume
3370 that there are none. */
3371 hrc = S_OK;
3372 for (int i = 0; i < cDevices && hrc == S_OK; i++)
3373 {
3374 char *pszDevNode = gLibHalDeviceGetPropertyString(halContext, halDevices[i], "block.device",
3375 &dbusError);
3376 /* The fixed drive ioctls work only for raw device nodes. */
3377 char *pszTmp = getfullrawname(pszDevNode);
3378 gLibHalFreeString(pszDevNode);
3379 pszDevNode = pszTmp;
3380 if (pszDevNode != 0)
3381 {
3382 /* We do not check the error here, as this field may
3383 not even exist. */
3384 char *pszVendor = gLibHalDeviceGetPropertyString(halContext, halDevices[i], "info.vendor", 0);
3385 char *pszProduct = gLibHalDeviceGetPropertyString(halContext, halDevices[i], "info.product",
3386 &dbusError);
3387 Utf8Str strDescription;
3388 if (pszProduct != NULL && pszProduct[0] != '\0')
3389 {
3390 int vrc;
3391 if (pszVendor != NULL && pszVendor[0] != '\0')
3392 vrc = strDescription.printfNoThrow("%s %s", pszVendor, pszProduct);
3393 else
3394 vrc = strDescription.assignNoThrow(pszProduct);
3395 AssertRCStmt(vrc, hrc = E_OUTOFMEMORY);
3396 }
3397 if (pszVendor != NULL)
3398 gLibHalFreeString(pszVendor);
3399 if (pszProduct != NULL)
3400 gLibHalFreeString(pszProduct);
3401
3402 /* Correct device/partition/slice already choosen. Just add it to the return list */
3403 if (hrc == S_OK)
3404 try
3405 {
3406 list.push_back(std::pair<com::Utf8Str, com::Utf8Str>(pszDevNode, strDescription));
3407 }
3408 catch (std::bad_alloc &)
3409 {
3410 AssertFailedStmt(hrc = E_OUTOFMEMORY);
3411 }
3412 gLibHalFreeString(pszDevNode);
3413 }
3414 else
3415 {
3416 LogRel(("Host::COMGETTER(HostDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
3417 halDevices[i], dbusError.name, dbusError.message));
3418 gDBusErrorFree(&dbusError);
3419 }
3420 }
3421 gLibHalFreeStringArray(halDevices);
3422 }
3423 else
3424 {
3425 LogRel(("Host::COMGETTER(HostDrives): failed to get devices with capability \"storage.disk\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
3426 gDBusErrorFree(&dbusError);
3427 }
3428 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
3429 {
3430 LogRel(("Host::COMGETTER(HostDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
3431 dbusError.name, dbusError.message));
3432 gDBusErrorFree(&dbusError);
3433 }
3434 }
3435 else
3436 {
3437 LogRel(("Host::COMGETTER(HostDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
3438 dbusError.name, dbusError.message));
3439 gDBusErrorFree(&dbusError);
3440 }
3441 gLibHalCtxFree(halContext);
3442 }
3443 else
3444 LogRel(("Host::COMGETTER(HostDrives): failed to set libhal connection to dbus.\n"));
3445 }
3446 else
3447 LogRel(("Host::COMGETTER(HostDrives): failed to get a libhal context - out of memory?\n"));
3448 gDBusConnectionUnref(dbusConnection);
3449 }
3450 else
3451 {
3452 LogRel(("Host::COMGETTER(HostDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3453 dbusError.name, dbusError.message));
3454 gDBusErrorFree(&dbusError);
3455 }
3456 return hrc;
3457}
3458
3459#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
3460
3461/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
3462#if defined(RT_OS_SOLARIS)
3463
3464/**
3465 * Helper function to parse the given mount file and add found entries
3466 */
3467void Host::i_parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
3468{
3469#ifdef RT_OS_LINUX
3470 FILE *mtab = setmntent(mountTable, "r");
3471 if (mtab)
3472 {
3473 struct mntent *mntent;
3474 char *mnt_type;
3475 char *mnt_dev;
3476 char *tmp;
3477 while ((mntent = getmntent(mtab)))
3478 {
3479 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
3480 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
3481 strcpy(mnt_type, mntent->mnt_type);
3482 strcpy(mnt_dev, mntent->mnt_fsname);
3483 // supermount fs case
3484 if (strcmp(mnt_type, "supermount") == 0)
3485 {
3486 tmp = strstr(mntent->mnt_opts, "fs=");
3487 if (tmp)
3488 {
3489 free(mnt_type);
3490 mnt_type = strdup(tmp + strlen("fs="));
3491 if (mnt_type)
3492 {
3493 tmp = strchr(mnt_type, ',');
3494 if (tmp)
3495 *tmp = '\0';
3496 }
3497 }
3498 tmp = strstr(mntent->mnt_opts, "dev=");
3499 if (tmp)
3500 {
3501 free(mnt_dev);
3502 mnt_dev = strdup(tmp + strlen("dev="));
3503 if (mnt_dev)
3504 {
3505 tmp = strchr(mnt_dev, ',');
3506 if (tmp)
3507 *tmp = '\0';
3508 }
3509 }
3510 }
3511 // use strstr here to cover things fs types like "udf,iso9660"
3512 if (strstr(mnt_type, "iso9660") == 0)
3513 {
3514 /** @todo check whether we've already got the drive in our list! */
3515 if (i_validateDevice(mnt_dev, true))
3516 {
3517 ComObjPtr<Medium> hostDVDDriveObj;
3518 hostDVDDriveObj.createObject();
3519 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
3520 list.push_back (hostDVDDriveObj);
3521 }
3522 }
3523 free(mnt_dev);
3524 free(mnt_type);
3525 }
3526 endmntent(mtab);
3527 }
3528#else // RT_OS_SOLARIS
3529 FILE *mntFile = fopen(mountTable, "r");
3530 if (mntFile)
3531 {
3532 struct mnttab mntTab;
3533 while (getmntent(mntFile, &mntTab) == 0)
3534 {
3535 const char *mountName = mntTab.mnt_special;
3536 const char *mountPoint = mntTab.mnt_mountp;
3537 const char *mountFSType = mntTab.mnt_fstype;
3538 if (mountName && mountPoint && mountFSType)
3539 {
3540 // skip devices we are not interested in
3541 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts,
3542 // proc, fd, swap)
3543 (*mountFSType && (strncmp(mountFSType, RT_STR_TUPLE("devfs")) != 0 && // skip devfs
3544 // (i.e. /devices)
3545 strncmp(mountFSType, RT_STR_TUPLE("dev")) != 0 && // skip dev (i.e. /dev)
3546 strncmp(mountFSType, RT_STR_TUPLE("lofs")) != 0))) // skip loop-back file-system (lofs)
3547 {
3548 char *rawDevName = getfullrawname((char *)mountName);
3549 if (i_validateDevice(rawDevName, true))
3550 {
3551 ComObjPtr<Medium> hostDVDDriveObj;
3552 hostDVDDriveObj.createObject();
3553 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
3554 list.push_back(hostDVDDriveObj);
3555 }
3556 free(rawDevName);
3557 }
3558 }
3559 }
3560
3561 fclose(mntFile);
3562 }
3563#endif
3564}
3565
3566/**
3567 * Helper function to check whether the given device node is a valid drive
3568 */
3569bool Host::i_validateDevice(const char *deviceNode, bool isCDROM)
3570{
3571 struct stat statInfo;
3572 bool retValue = false;
3573
3574 // sanity check
3575 if (!deviceNode)
3576 {
3577 return false;
3578 }
3579
3580 // first a simple stat() call
3581 if (stat(deviceNode, &statInfo) < 0)
3582 {
3583 return false;
3584 }
3585 else
3586 {
3587 if (isCDROM)
3588 {
3589 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
3590 {
3591 int fileHandle;
3592 // now try to open the device
3593 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
3594 if (fileHandle >= 0)
3595 {
3596 cdrom_subchnl cdChannelInfo;
3597 cdChannelInfo.cdsc_format = CDROM_MSF;
3598 // this call will finally reveal the whole truth
3599#ifdef RT_OS_LINUX
3600 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
3601 (errno == EIO) || (errno == ENOENT) ||
3602 (errno == EINVAL) || (errno == ENOMEDIUM))
3603#else
3604 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
3605 (errno == EIO) || (errno == ENOENT) ||
3606 (errno == EINVAL))
3607#endif
3608 {
3609 retValue = true;
3610 }
3611 close(fileHandle);
3612 }
3613 }
3614 } else
3615 {
3616 // floppy case
3617 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
3618 {
3619 /// @todo do some more testing, maybe a nice IOCTL!
3620 retValue = true;
3621 }
3622 }
3623 }
3624 return retValue;
3625}
3626#endif // RT_OS_SOLARIS
3627
3628#ifdef VBOX_WITH_USB
3629/**
3630 * Checks for the presence and status of the USB Proxy Service.
3631 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
3632 * warning) if the proxy service is not available due to the way the host is
3633 * configured (at present, that means that usbfs and hal/DBus are not
3634 * available on a Linux host) or E_FAIL and a corresponding error message
3635 * otherwise. Intended to be used by methods that rely on the Proxy Service
3636 * availability.
3637 *
3638 * @note This method may return a warning result code. It is recommended to use
3639 * MultiError to store the return value.
3640 *
3641 * @note Locks this object for reading.
3642 */
3643HRESULT Host::i_checkUSBProxyService()
3644{
3645 AutoCaller autoCaller(this);
3646 if (FAILED(autoCaller.hrc()))
3647 return autoCaller.hrc();
3648
3649 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3650
3651 AssertReturn(m->pUSBProxyService, E_FAIL);
3652 if (!m->pUSBProxyService->isActive())
3653 {
3654 /* disable the USB controller completely to avoid assertions if the
3655 * USB proxy service could not start. */
3656
3657 switch (m->pUSBProxyService->getLastError())
3658 {
3659 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
3660 return setWarning(E_FAIL,
3661 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
3662 case VERR_VUSB_USB_DEVICE_PERMISSION:
3663 return setWarning(E_FAIL,
3664 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"));
3665 case VERR_VUSB_USBFS_PERMISSION:
3666 return setWarning(E_FAIL,
3667 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"));
3668 case VINF_SUCCESS:
3669 return setWarning(E_FAIL,
3670 tr("The USB Proxy Service has not yet been ported to this host"));
3671 default:
3672 return setWarning(E_FAIL, "%s: %Rrc",
3673 tr("Could not load the Host USB Proxy service"),
3674 m->pUSBProxyService->getLastError());
3675 }
3676 }
3677
3678 return S_OK;
3679}
3680#endif /* VBOX_WITH_USB */
3681
3682HRESULT Host::i_updateNetIfList()
3683{
3684#ifdef VBOX_WITH_HOSTNETIF_API
3685 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
3686
3687 /** @todo r=klaus it would save lots of clock cycles if for concurrent
3688 * threads executing this code we'd only do one interface enumeration
3689 * and update, and let the other threads use the result as is. However
3690 * if there's a constant hammering of this method, we don't want this
3691 * to cause update starvation. */
3692 HostNetworkInterfaceList list;
3693 int vrc = NetIfList(list);
3694 if (RT_FAILURE(vrc))
3695 {
3696 Log(("Failed to get host network interface list with vrc=%Rrc\n", vrc));
3697 return E_FAIL;
3698 }
3699
3700 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3701
3702 AssertReturn(m->pParent, E_FAIL);
3703 /* Make a copy as the original may be partially destroyed later. */
3704 HostNetworkInterfaceList listCopy(list);
3705 HostNetworkInterfaceList::iterator itOld, itNew;
3706# ifdef VBOX_WITH_RESOURCE_USAGE_API
3707 PerformanceCollector *aCollector = m->pParent->i_performanceCollector();
3708# endif
3709 for (itOld = m->llNetIfs.begin(); itOld != m->llNetIfs.end(); ++itOld)
3710 {
3711 bool fGone = true;
3712 Bstr nameOld;
3713 (*itOld)->COMGETTER(Name)(nameOld.asOutParam());
3714 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
3715 {
3716 Bstr nameNew;
3717 (*itNew)->COMGETTER(Name)(nameNew.asOutParam());
3718 if (nameNew == nameOld)
3719 {
3720 fGone = false;
3721 (*itNew)->uninit();
3722 listCopy.erase(itNew);
3723 break;
3724 }
3725 }
3726 if (fGone)
3727 {
3728# ifdef VBOX_WITH_RESOURCE_USAGE_API
3729 (*itOld)->i_unregisterMetrics(aCollector, this);
3730 (*itOld)->uninit();
3731# endif
3732 }
3733 }
3734 /*
3735 * Need to set the references to VirtualBox object in all interface objects
3736 * (see @bugref{6439}).
3737 */
3738 for (itNew = list.begin(); itNew != list.end(); ++itNew)
3739 (*itNew)->i_setVirtualBox(m->pParent);
3740 /* At this point listCopy will contain newly discovered interfaces only. */
3741 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
3742 {
3743 HostNetworkInterfaceType_T t;
3744 HRESULT hrc = (*itNew)->COMGETTER(InterfaceType)(&t);
3745 if (FAILED(hrc))
3746 {
3747 Bstr n;
3748 (*itNew)->COMGETTER(Name)(n.asOutParam());
3749 LogRel(("Host::updateNetIfList: failed to get interface type for %ls\n", n.raw()));
3750 }
3751 else if (t == HostNetworkInterfaceType_Bridged)
3752 {
3753# ifdef VBOX_WITH_RESOURCE_USAGE_API
3754 (*itNew)->i_registerMetrics(aCollector, this);
3755# endif
3756 }
3757 }
3758 m->llNetIfs = list;
3759 return S_OK;
3760#else
3761 return E_NOTIMPL;
3762#endif
3763}
3764
3765#ifdef VBOX_WITH_RESOURCE_USAGE_API
3766
3767void Host::i_registerDiskMetrics(PerformanceCollector *aCollector)
3768{
3769 pm::CollectorHAL *hal = aCollector->getHAL();
3770 /* Create sub metrics */
3771 Utf8StrFmt fsNameBase("FS/{%s}/Usage", "/");
3772 //Utf8StrFmt fsNameBase("Filesystem/[root]/Usage");
3773 pm::SubMetric *fsRootUsageTotal = new pm::SubMetric(fsNameBase + "/Total",
3774 "Root file system size.");
3775 pm::SubMetric *fsRootUsageUsed = new pm::SubMetric(fsNameBase + "/Used",
3776 "Root file system space currently occupied.");
3777 pm::SubMetric *fsRootUsageFree = new pm::SubMetric(fsNameBase + "/Free",
3778 "Root file system space currently empty.");
3779
3780 pm::BaseMetric *fsRootUsage = new pm::HostFilesystemUsage(hal, this,
3781 fsNameBase, "/",
3782 fsRootUsageTotal,
3783 fsRootUsageUsed,
3784 fsRootUsageFree);
3785 aCollector->registerBaseMetric(fsRootUsage);
3786
3787 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal, 0));
3788 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3789 new pm::AggregateAvg()));
3790 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3791 new pm::AggregateMin()));
3792 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3793 new pm::AggregateMax()));
3794
3795 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed, 0));
3796 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3797 new pm::AggregateAvg()));
3798 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3799 new pm::AggregateMin()));
3800 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3801 new pm::AggregateMax()));
3802
3803 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree, 0));
3804 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3805 new pm::AggregateAvg()));
3806 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3807 new pm::AggregateMin()));
3808 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3809 new pm::AggregateMax()));
3810
3811 /* For now we are concerned with the root file system only. */
3812 pm::DiskList disksUsage, disksLoad;
3813 int vrc = hal->getDiskListByFs("/", disksUsage, disksLoad);
3814 if (RT_FAILURE(vrc))
3815 return;
3816 pm::DiskList::iterator it;
3817 for (it = disksLoad.begin(); it != disksLoad.end(); ++it)
3818 {
3819 Utf8StrFmt strName("Disk/%s", it->c_str());
3820 pm::SubMetric *fsLoadUtil = new pm::SubMetric(strName + "/Load/Util",
3821 "Percentage of time disk was busy serving I/O requests.");
3822 pm::BaseMetric *fsLoad = new pm::HostDiskLoadRaw(hal, this, strName + "/Load",
3823 *it, fsLoadUtil);
3824 aCollector->registerBaseMetric(fsLoad);
3825
3826 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil, 0));
3827 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3828 new pm::AggregateAvg()));
3829 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3830 new pm::AggregateMin()));
3831 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3832 new pm::AggregateMax()));
3833 }
3834 for (it = disksUsage.begin(); it != disksUsage.end(); ++it)
3835 {
3836 Utf8StrFmt strName("Disk/%s", it->c_str());
3837 pm::SubMetric *fsUsageTotal = new pm::SubMetric(strName + "/Usage/Total",
3838 "Disk size.");
3839 pm::BaseMetric *fsUsage = new pm::HostDiskUsage(hal, this, strName + "/Usage",
3840 *it, fsUsageTotal);
3841 aCollector->registerBaseMetric(fsUsage);
3842
3843 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, 0));
3844 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3845 new pm::AggregateAvg()));
3846 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3847 new pm::AggregateMin()));
3848 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3849 new pm::AggregateMax()));
3850 }
3851}
3852
3853void Host::i_registerMetrics(PerformanceCollector *aCollector)
3854{
3855 pm::CollectorHAL *hal = aCollector->getHAL();
3856 /* Create sub metrics */
3857 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
3858 "Percentage of processor time spent in user mode.");
3859 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
3860 "Percentage of processor time spent in kernel mode.");
3861 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
3862 "Percentage of processor time spent idling.");
3863 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
3864 "Average of current frequency of all processors.");
3865 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
3866 "Total physical memory installed.");
3867 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
3868 "Physical memory currently occupied.");
3869 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
3870 "Physical memory currently available to applications.");
3871 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
3872 "Total physical memory used by the hypervisor.");
3873 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
3874 "Total physical memory free inside the hypervisor.");
3875 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
3876 "Total physical memory ballooned by the hypervisor.");
3877 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
3878 "Total physical memory shared between VMs.");
3879
3880
3881 /* Create and register base metrics */
3882 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, this, cpuLoadUser, cpuLoadKernel,
3883 cpuLoadIdle);
3884 aCollector->registerBaseMetric(cpuLoad);
3885 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, this, cpuMhzSM);
3886 aCollector->registerBaseMetric(cpuMhz);
3887 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, this,
3888 ramUsageTotal,
3889 ramUsageUsed,
3890 ramUsageFree);
3891 aCollector->registerBaseMetric(ramUsage);
3892 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), this,
3893 ramVMMUsed,
3894 ramVMMFree,
3895 ramVMMBallooned,
3896 ramVMMShared);
3897 aCollector->registerBaseMetric(ramVmm);
3898
3899 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
3900 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3901 new pm::AggregateAvg()));
3902 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3903 new pm::AggregateMin()));
3904 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3905 new pm::AggregateMax()));
3906
3907 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
3908 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3909 new pm::AggregateAvg()));
3910 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3911 new pm::AggregateMin()));
3912 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3913 new pm::AggregateMax()));
3914
3915 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
3916 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3917 new pm::AggregateAvg()));
3918 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3919 new pm::AggregateMin()));
3920 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3921 new pm::AggregateMax()));
3922
3923 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
3924 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3925 new pm::AggregateAvg()));
3926 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3927 new pm::AggregateMin()));
3928 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3929 new pm::AggregateMax()));
3930
3931 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
3932 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3933 new pm::AggregateAvg()));
3934 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3935 new pm::AggregateMin()));
3936 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3937 new pm::AggregateMax()));
3938
3939 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
3940 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3941 new pm::AggregateAvg()));
3942 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3943 new pm::AggregateMin()));
3944 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3945 new pm::AggregateMax()));
3946
3947 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
3948 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3949 new pm::AggregateAvg()));
3950 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3951 new pm::AggregateMin()));
3952 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3953 new pm::AggregateMax()));
3954
3955 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
3956 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3957 new pm::AggregateAvg()));
3958 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3959 new pm::AggregateMin()));
3960 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3961 new pm::AggregateMax()));
3962
3963 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
3964 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3965 new pm::AggregateAvg()));
3966 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3967 new pm::AggregateMin()));
3968 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3969 new pm::AggregateMax()));
3970
3971 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
3972 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3973 new pm::AggregateAvg()));
3974 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3975 new pm::AggregateMin()));
3976 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3977 new pm::AggregateMax()));
3978
3979 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
3980 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3981 new pm::AggregateAvg()));
3982 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3983 new pm::AggregateMin()));
3984 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3985 new pm::AggregateMax()));
3986 i_registerDiskMetrics(aCollector);
3987}
3988
3989void Host::i_unregisterMetrics(PerformanceCollector *aCollector)
3990{
3991 aCollector->unregisterMetricsFor(this);
3992 aCollector->unregisterBaseMetricsFor(this);
3993}
3994
3995#endif /* VBOX_WITH_RESOURCE_USAGE_API */
3996
3997
3998/* static */
3999void Host::i_generateMACAddress(Utf8Str &mac)
4000{
4001 /*
4002 * Our strategy is as follows: the first three bytes are our fixed
4003 * vendor ID (080027). The remaining 3 bytes will be taken from the
4004 * start of a GUID. This is a fairly safe algorithm.
4005 */
4006 Guid guid;
4007 guid.create();
4008 mac = Utf8StrFmt("080027%02X%02X%02X",
4009 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
4010}
4011
4012/**
4013 * Returns the host's platform architecture.
4014 *
4015 * @returns The host's platform architecture.
4016 */
4017/* static */
4018PlatformArchitecture_T Host::s_getPlatformArchitecture()
4019{
4020#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
4021 return PlatformArchitecture_x86;
4022#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
4023 return PlatformArchitecture_ARM;
4024#else
4025# error "Port me!"
4026 return PlatformArchitecture_None;
4027#endif
4028}
4029
4030#ifdef RT_OS_WINDOWS
4031HRESULT Host::i_getFixedDrivesFromGlobalNamespace(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &aDriveList) RT_NOEXCEPT
4032{
4033 RTERRINFOSTATIC ErrInfo;
4034 uint32_t offError;
4035 RTVFSDIR hVfsDir;
4036 int vrc = RTVfsChainOpenDir("\\\\:iprtnt:\\GLOBAL??", 0 /*fFlags*/, &hVfsDir, &offError, RTErrInfoInitStatic(&ErrInfo));
4037 if (RT_FAILURE(vrc))
4038 return setError(E_FAIL, tr("Failed to open NT\\GLOBAL?? (error %Rrc)"), vrc);
4039
4040 /*
4041 * Scan whole directory and find any 'PhysicalDiskX' entries. Next, combine with '\\.\'
4042 * to obtain the harddisk dev path.
4043 */
4044 size_t cbDirEntryAlloced = sizeof(RTDIRENTRYEX);
4045 PRTDIRENTRYEX pDirEntry = (PRTDIRENTRYEX)RTMemTmpAlloc(cbDirEntryAlloced);
4046 if (!pDirEntry)
4047 {
4048 RTVfsDirRelease(hVfsDir);
4049 return setError(E_OUTOFMEMORY, tr("Out of memory! (direntry buffer)"));
4050 }
4051
4052 HRESULT hrc = S_OK;
4053 for (;;)
4054 {
4055 size_t cbDirEntry = cbDirEntryAlloced;
4056 vrc = RTVfsDirReadEx(hVfsDir, pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING);
4057 if (RT_FAILURE(vrc))
4058 {
4059 if (vrc == VERR_BUFFER_OVERFLOW)
4060 {
4061 RTMemTmpFree(pDirEntry);
4062 cbDirEntryAlloced = RT_ALIGN_Z(RT_MIN(cbDirEntry, cbDirEntryAlloced) + 64, 64);
4063 pDirEntry = (PRTDIRENTRYEX)RTMemTmpAlloc(cbDirEntryAlloced);
4064 if (pDirEntry)
4065 continue;
4066 hrc = setError(E_OUTOFMEMORY, tr("Out of memory! (direntry buffer)"));
4067 }
4068 else if (vrc != VERR_NO_MORE_FILES)
4069 hrc = setError(VBOX_E_IPRT_ERROR, tr("RTVfsDirReadEx failed: %Rrc"), vrc);
4070 break;
4071 }
4072 if (RTStrStartsWith(pDirEntry->szName, "PhysicalDrive"))
4073 {
4074 char szPhysicalDrive[64];
4075 RTStrPrintf(szPhysicalDrive, sizeof(szPhysicalDrive), "\\\\.\\%s", pDirEntry->szName);
4076
4077 RTFILE hRawFile = NIL_RTFILE;
4078 vrc = RTFileOpen(&hRawFile, szPhysicalDrive, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
4079 if (RT_FAILURE(vrc))
4080 {
4081 try
4082 {
4083 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(szPhysicalDrive, tr("Unknown (Access denied)")));
4084 }
4085 catch (std::bad_alloc &)
4086 {
4087 hrc = setError(E_OUTOFMEMORY, tr("Out of memory"));
4088 break;
4089 }
4090 continue;
4091 }
4092
4093 DWORD cbBytesReturned = 0;
4094 uint8_t abBuffer[1024];
4095 RT_ZERO(abBuffer);
4096
4097 STORAGE_PROPERTY_QUERY query;
4098 RT_ZERO(query);
4099 query.PropertyId = StorageDeviceProperty;
4100 query.QueryType = PropertyStandardQuery;
4101
4102 BOOL fRc = DeviceIoControl((HANDLE)RTFileToNative(hRawFile),
4103 IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query),
4104 abBuffer, sizeof(abBuffer), &cbBytesReturned, NULL);
4105 RTFileClose(hRawFile);
4106 char szModel[1024];
4107 if (fRc)
4108 {
4109 PSTORAGE_DEVICE_DESCRIPTOR pDevDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)abBuffer;
4110 char *pszProduct = pDevDescriptor->ProductIdOffset ? (char *)&abBuffer[pDevDescriptor->ProductIdOffset] : NULL;
4111 if (pszProduct)
4112 {
4113 RTStrPurgeEncoding(pszProduct);
4114 if (*pszProduct != '\0')
4115 {
4116 char *pszVendor = pDevDescriptor->VendorIdOffset ? (char *)&abBuffer[pDevDescriptor->VendorIdOffset] : NULL;
4117 if (pszVendor)
4118 RTStrPurgeEncoding(pszVendor);
4119 if (pszVendor && *pszVendor)
4120 RTStrPrintf(szModel, sizeof(szModel), "%s %s", pszVendor, pszProduct);
4121 else
4122 RTStrCopy(szModel, sizeof(szModel), pszProduct);
4123 }
4124 }
4125 }
4126 try
4127 {
4128 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(szPhysicalDrive, szModel));
4129 }
4130 catch (std::bad_alloc &)
4131 {
4132 hrc = setError(E_OUTOFMEMORY, tr("Out of memory"));
4133 break;
4134 }
4135 }
4136 }
4137 if (FAILED(hrc))
4138 aDriveList.clear();
4139 RTMemTmpFree(pDirEntry);
4140 RTVfsDirRelease(hVfsDir);
4141 return hrc;
4142}
4143#endif
4144
4145/**
4146 * @throws nothing
4147 */
4148HRESULT Host::i_getDrivesPathsList(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &aDriveList) RT_NOEXCEPT
4149{
4150#ifdef RT_OS_WINDOWS
4151 return i_getFixedDrivesFromGlobalNamespace(aDriveList);
4152
4153#elif defined(RT_OS_DARWIN)
4154 /*
4155 * Get the list of fixed drives from iokit.cpp and transfer it to aDriveList.
4156 */
4157 PDARWINFIXEDDRIVE pDrives = DarwinGetFixedDrives();
4158 HRESULT hrc;
4159 try
4160 {
4161 for (PDARWINFIXEDDRIVE pCurDrv = pDrives; pCurDrv; pCurDrv = pCurDrv->pNext)
4162 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(pCurDrv->szName, pCurDrv->pszModel));
4163 hrc = S_OK;
4164 }
4165 catch (std::bad_alloc &)
4166 {
4167 aDriveList.clear();
4168 hrc = E_OUTOFMEMORY;
4169 }
4170
4171 while (pDrives)
4172 {
4173 PDARWINFIXEDDRIVE pFreeMe = pDrives;
4174 pDrives = pDrives->pNext;
4175 ASMCompilerBarrier();
4176 RTMemFree(pFreeMe);
4177 }
4178 return hrc;
4179
4180#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
4181 /*
4182 * The list of fixed drives is kept in the VBoxMainDriveInfo instance, so
4183 * update it and tranfer the info to aDriveList.
4184 *
4185 * This obviously requires us to write lock the object!
4186 */
4187 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4188 int vrc = m->hostDrives.updateFixedDrives(); /* nothrow */
4189 if (RT_FAILURE(vrc))
4190 return setErrorBoth(E_FAIL, vrc, tr("Failed to update fixed drive list (%Rrc)"), vrc);
4191
4192 try
4193 {
4194 for (DriveInfoList::const_iterator it = m->hostDrives.FixedDriveBegin(); it != m->hostDrives.FixedDriveEnd(); ++it)
4195 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(it->mDevice, it->mDescription));
4196 }
4197 catch (std::bad_alloc &)
4198 {
4199 aDriveList.clear();
4200 return E_OUTOFMEMORY;
4201 }
4202 return S_OK;
4203
4204#elif defined(RT_OS_SOLARIS)
4205 /*
4206 * We can get the info from HAL, if not present/working we'll get by
4207 * walking the device tree.
4208 */
4209# ifdef VBOX_USE_LIBHAL
4210 HRESULT hrc = i_getFixedDrivesFromHal(aDriveList);
4211 if (hrc != S_FALSE)
4212 return hrc;
4213 aDriveList.clear(); /* just in case */
4214# endif
4215 return i_getFixedDrivesFromDevTree(aDriveList);
4216
4217#else
4218 /* PORTME */
4219 RT_NOREF(aDriveList);
4220 return E_NOTIMPL;
4221#endif
4222}
4223
4224
4225#ifdef VBOX_WITH_NATIVE_NEM
4226BOOL Host::i_HostIsNativeApiSupported()
4227{
4228# ifdef RT_OS_WINDOWS
4229 WCHAR wszPath[MAX_PATH + 64];
4230 UINT cwcPath = GetSystemDirectoryW(wszPath, MAX_PATH);
4231 if (cwcPath >= MAX_PATH || cwcPath < 2)
4232 return FALSE;
4233
4234 if (wszPath[cwcPath - 1] != '\\' || wszPath[cwcPath - 1] != '/')
4235 wszPath[cwcPath++] = '\\';
4236 RTUtf16CopyAscii(&wszPath[cwcPath], RT_ELEMENTS(wszPath) - cwcPath, "WinHvPlatform.dll");
4237 if (GetFileAttributesW(wszPath) == INVALID_FILE_ATTRIBUTES)
4238 return FALSE;
4239
4240# ifdef RT_ARCH_AMD64
4241 /*
4242 * Check that we're in a VM and that the hypervisor identifies itself as Hyper-V.
4243 */
4244 if (!ASMHasCpuId())
4245 return FALSE;
4246 if (!RTX86IsValidStdRange(ASMCpuId_EAX(0)))
4247 return FALSE;
4248 if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_HVP))
4249 return FALSE;
4250
4251 uint32_t cMaxHyperLeaf = 0;
4252 uint32_t uEbx = 0;
4253 uint32_t uEcx = 0;
4254 uint32_t uEdx = 0;
4255 ASMCpuIdExSlow(0x40000000, 0, 0, 0, &cMaxHyperLeaf, &uEbx, &uEcx, &uEdx);
4256 if (!RTX86IsValidHypervisorRange(cMaxHyperLeaf))
4257 return FALSE;
4258 if ( uEbx != UINT32_C(0x7263694d) /* Micr */
4259 || uEcx != UINT32_C(0x666f736f) /* osof */
4260 || uEdx != UINT32_C(0x76482074) /* t Hv */)
4261 return FALSE;
4262 if (cMaxHyperLeaf >= UINT32_C(0x40000005))
4263 return TRUE;
4264# endif
4265# elif defined(RT_OS_LINUX)
4266 int fdKvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
4267 if (fdKvm >= 0)
4268 {
4269 /** @todo Do we need to do anything else here? */
4270 close(fdKvm);
4271 return TRUE;
4272 }
4273# elif defined(RT_OS_DARWIN)
4274 /*
4275 * The kern.hv_support parameter indicates support for the hypervisor API
4276 * in the kernel.
4277 */
4278 int32_t fHvSupport = 0;
4279 size_t cbOld = sizeof(fHvSupport);
4280 if (sysctlbyname("kern.hv_support", &fHvSupport, &cbOld, NULL, 0) == 0)
4281 {
4282 if (fHvSupport != 0)
4283 return TRUE;
4284 }
4285# endif
4286 return FALSE;
4287}
4288#endif
4289
4290
4291/* 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