VirtualBox

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

Last change on this file since 94722 was 94722, checked in by vboxsync, 3 years ago

Main: Compile fixes when VBOX_WITH_HOSTNETIF_API is not defined.

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

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