VirtualBox

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

最後變更 在這個檔案從98288是 98288,由 vboxsync 提交於 2 年 前

Main/src-server: rc -> hrc/vrc (partial). bugref:10223

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