VirtualBox

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

最後變更 在這個檔案從101057是 101035,由 vboxsync 提交於 19 月 前

Initial commit (based draft v2 / on patch v5) for implementing platform architecture support for x86 and ARM. bugref:10384

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

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