VirtualBox

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

Last change on this file since 99599 was 98294, checked in by vboxsync, 21 months ago

Main/src-server: hr -> hrc. bugref:10223

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

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