VirtualBox

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

最後變更 在這個檔案從99941是 99941,由 vboxsync 提交於 22 月 前

Main, FE/Qt: Wiping out old OpenGLTest code used widely across the project.

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

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