VirtualBox

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

最後變更 在這個檔案從108422是 107797,由 vboxsync 提交於 2 月 前

Main/HostImpl.cpp: Fixed lock order problem in Host::i_updateNetIfList / HostNetworkInterface::i_setVirtualBox / VirtualBox::getExtraData after r166866.

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

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