VirtualBox

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

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

iprt/asm-amd64-x86.h: Split out some non-assembly functions that related more to x86.h than to asm.h, changing the function prefix from ASM to RTX86. bugref:9898

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