VirtualBox

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

Last change on this file was 101684, checked in by vboxsync, 6 months ago

Main/Host: Set the hwvirt++ flags on arm64 accordingly so the validationkit can select the proper VM configs for testing, bugref:10542

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

© 2023 Oracle
ContactPrivacy policyTerms of Use