VirtualBox

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

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

Main: Don't known why we didn't enable the Host::getAcceleration3DAvailable functionality, forgot/lost passing on the VBOX_WITH_3D_ACCELERATION define in the Makefile.kmk perhaps, let's see what happens when we define it now.

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