VirtualBox

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

Last change on this file since 101381 was 101176, checked in by vboxsync, 9 months ago

Main: Added a new static function Host::s_getPlatformArchitecture() for easier retrieving the host's platform architecture internally. bugref:10384

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

© 2023 Oracle
ContactPrivacy policyTerms of Use