VirtualBox

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

Last change on this file since 107597 was 107523, checked in by vboxsync, 3 weeks ago

src/VBox/Main/src-server/HostImpl.cpp: Fixed warning found by Parfait (uninitialized attributes). jiraref:VBP-1424

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

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