VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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

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