VirtualBox

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

Last change on this file since 105659 was 105254, checked in by vboxsync, 5 months ago

Main,FE/VBoxManage: Add method to query which execution engines supported by a build are actually supported by the host. Primarily for querying whether the native API is accessible on a host

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