VirtualBox

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

Last change on this file since 104956 was 104635, checked in by vboxsync, 7 months ago

Main: Fixed warnings. ​bugref:3409

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