VirtualBox

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

Last change on this file since 100842 was 100772, checked in by vboxsync, 21 months ago

include/VBox/usbfilter.h,HostDrivers/VBoxUSB/USBFilter: IUSBDeviceFilter:
USB device interval filters don't work. bugref:10452

Main/Host,Main/USBDeviceFilter: Adding or removing global USB device
filters causes memory corruption wihch can lead to a deadlock or a SEGV
as the list of global USB device filters (llChildren) changes while
the list is being walked.

Frontends/VBoxManage: 'VBoxManage list usbfilters' doesn't display the
'Port' value of the device filter.

Frontends/VBoxManage: 'VBoxManage add usbfilter' and 'VBoxManage modify
usbfilter' both ignore the --product="Value" option.

Main/VirtualBox.xidl: Improve the IUSBDeviceFilter wording to make
things clearer in the 'VirtualBox Programming Guide and Reference Guide'
aka SDKRef.pdf.

HostDrivers/VBoxUSB/testcase/tstUSBFilter: Include a variety of USB
device filter entries which include the 'int:' prefix to fully exercise
the interval filter parsing code.

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

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