VirtualBox

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

Last change on this file since 95423 was 95423, checked in by vboxsync, 3 years ago

Audio/Main: Bigger revamp of the audio interface(s) to later also support host audio device enumeration and selection for individual VMs. The audio settings now live in a dedicated (per-VM) IAudioSettings interface (audio adapter + audio host device stuff), to further tidy up the IMachine interface. Also added stubs for IAudioDevice + IHostAudioDevice, plus enmuerations, left for further implementation. Added a new IHostAudioDeviceChangedEvent that can also be used later by API clients. bugref:10050

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

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