VirtualBox

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

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

Main: bugref:1909: Added missed translation marks, removed redundant ones. Expanded one macro to make the lupdate get string correctly. Removed GuestBase::setErrorExternal and changed calls from it to setErrorBoth to handle translation correctly.

  • 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 91503 2021-10-01 08:57:59Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Host
4 */
5
6/*
7 * Copyright (C) 2004-2020 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 (ASMIsValidStdRange(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 = ASMIsValidExtRange(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 ( ASMIsIntelCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
362 || ASMIsViaCentaurCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
363 || ASMIsShanghaiCpuEx(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 ( ASMIsAmdCpuEx(uVendorEBX, uVendorECX, uVendorEDX)
378 || ASMIsHygonCpuEx(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 && ASMIsValidExtRange(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 char szCPUModel[80];
1163 szCPUModel[0] = 0;
1164 int vrc = RTMpGetDescription(aCpuId, szCPUModel, sizeof(szCPUModel));
1165 if (RT_FAILURE(vrc))
1166 return E_FAIL; /** @todo error reporting? */
1167
1168 aDescription = Utf8Str(szCPUModel);
1169
1170 return S_OK;
1171}
1172
1173/**
1174 * Updates fVTSupported, fNestedPagingSupported, fUnrestrictedGuestSupported,
1175 * fVirtVmsaveVmload and fNestedHWVirtSupported with info from SUPR3QueryVTCaps().
1176 *
1177 * This is repeated till we successfully open the support driver, in case it
1178 * is loaded after VBoxSVC starts.
1179 */
1180void Host::i_updateProcessorFeatures()
1181{
1182 /* Perhaps the driver is available now... */
1183 int rc = SUPR3InitEx(false /*fUnrestricted*/, NULL);
1184 if (RT_SUCCESS(rc))
1185 {
1186 uint32_t fVTCaps;
1187 rc = SUPR3QueryVTCaps(&fVTCaps);
1188 AssertMsgRC(rc, ("SUPR3QueryVTCaps failed rc=%Rrc\n", rc));
1189
1190 SUPR3Term(false);
1191
1192 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
1193 if (RT_FAILURE(rc))
1194 {
1195 LogRel(("SUPR0QueryVTCaps -> %Rrc\n", rc));
1196 fVTCaps = 0;
1197 }
1198 m->fVTSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VT_X)) != 0;
1199 m->fNestedPagingSupported = (fVTCaps & SUPVTCAPS_NESTED_PAGING) != 0;
1200 m->fUnrestrictedGuestSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_VTX_UNRESTRICTED_GUEST)) != 0;
1201 m->fNestedHWVirtSupported = (fVTCaps & (SUPVTCAPS_AMD_V | SUPVTCAPS_NESTED_PAGING))
1202 == (SUPVTCAPS_AMD_V | SUPVTCAPS_NESTED_PAGING)
1203 || (fVTCaps & ( SUPVTCAPS_VT_X | SUPVTCAPS_NESTED_PAGING
1204 | SUPVTCAPS_VTX_UNRESTRICTED_GUEST | SUPVTCAPS_VTX_VMCS_SHADOWING))
1205 == ( SUPVTCAPS_VT_X | SUPVTCAPS_NESTED_PAGING
1206 | SUPVTCAPS_VTX_UNRESTRICTED_GUEST | SUPVTCAPS_VTX_VMCS_SHADOWING);
1207 m->fVirtVmsaveVmload = (fVTCaps & SUPVTCAPS_AMDV_VIRT_VMSAVE_VMLOAD) != 0;
1208 m->fRecheckVTSupported = false; /* No need to try again, we cached everything. */
1209 }
1210}
1211
1212/**
1213 * Returns whether a host processor feature is supported or not
1214 *
1215 * @returns COM status code
1216 * @param aFeature to query.
1217 * @param aSupported supported bool result variable
1218 */
1219HRESULT Host::getProcessorFeature(ProcessorFeature_T aFeature, BOOL *aSupported)
1220{
1221 /* Validate input. */
1222 switch (aFeature)
1223 {
1224 case ProcessorFeature_HWVirtEx:
1225 case ProcessorFeature_PAE:
1226 case ProcessorFeature_LongMode:
1227 case ProcessorFeature_NestedPaging:
1228 case ProcessorFeature_UnrestrictedGuest:
1229 case ProcessorFeature_NestedHWVirt:
1230 case ProcessorFeature_VirtVmsaveVmload:
1231 break;
1232 default:
1233 return setError(E_INVALIDARG, tr("The aFeature value %d (%#x) is out of range."), (int)aFeature, (int)aFeature);
1234 }
1235
1236 /* Do the job. */
1237 AutoCaller autoCaller(this);
1238 HRESULT hrc = autoCaller.rc();
1239 if (SUCCEEDED(hrc))
1240 {
1241 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1242
1243 if ( m->fRecheckVTSupported
1244 && ( aFeature == ProcessorFeature_HWVirtEx
1245 || aFeature == ProcessorFeature_NestedPaging
1246 || aFeature == ProcessorFeature_UnrestrictedGuest
1247 || aFeature == ProcessorFeature_NestedHWVirt
1248 || aFeature == ProcessorFeature_VirtVmsaveVmload)
1249 )
1250 {
1251 alock.release();
1252 i_updateProcessorFeatures();
1253 alock.acquire();
1254 }
1255
1256 switch (aFeature)
1257 {
1258 case ProcessorFeature_HWVirtEx:
1259 *aSupported = m->fVTSupported;
1260 break;
1261
1262 case ProcessorFeature_PAE:
1263 *aSupported = m->fPAESupported;
1264 break;
1265
1266 case ProcessorFeature_LongMode:
1267 *aSupported = m->fLongModeSupported;
1268 break;
1269
1270 case ProcessorFeature_NestedPaging:
1271 *aSupported = m->fNestedPagingSupported;
1272 break;
1273
1274 case ProcessorFeature_UnrestrictedGuest:
1275 *aSupported = m->fUnrestrictedGuestSupported;
1276 break;
1277
1278 case ProcessorFeature_NestedHWVirt:
1279 *aSupported = m->fNestedHWVirtSupported;
1280 break;
1281
1282 case ProcessorFeature_VirtVmsaveVmload:
1283 *aSupported = m->fVirtVmsaveVmload;
1284 break;
1285
1286 default:
1287 AssertFailed();
1288 }
1289 }
1290 return hrc;
1291}
1292
1293/**
1294 * Returns the specific CPUID leaf.
1295 *
1296 * @returns COM status code
1297 * @param aCpuId The CPU number. Mostly ignored.
1298 * @param aLeaf The leaf number.
1299 * @param aSubLeaf The sub-leaf number.
1300 * @param aValEAX Where to return EAX.
1301 * @param aValEBX Where to return EBX.
1302 * @param aValECX Where to return ECX.
1303 * @param aValEDX Where to return EDX.
1304 */
1305HRESULT Host::getProcessorCPUIDLeaf(ULONG aCpuId, ULONG aLeaf, ULONG aSubLeaf,
1306 ULONG *aValEAX, ULONG *aValEBX, ULONG *aValECX, ULONG *aValEDX)
1307{
1308 // no locking required
1309
1310 /* Check that the CPU is online. */
1311 /** @todo later use RTMpOnSpecific. */
1312 if (!RTMpIsCpuOnline(aCpuId))
1313 return RTMpIsCpuPresent(aCpuId)
1314 ? setError(E_FAIL, tr("CPU no.%u is not present"), aCpuId)
1315 : setError(E_FAIL, tr("CPU no.%u is not online"), aCpuId);
1316
1317#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
1318 uint32_t uEAX, uEBX, uECX, uEDX;
1319 ASMCpuId_Idx_ECX(aLeaf, aSubLeaf, &uEAX, &uEBX, &uECX, &uEDX);
1320 *aValEAX = uEAX;
1321 *aValEBX = uEBX;
1322 *aValECX = uECX;
1323 *aValEDX = uEDX;
1324#else
1325 *aValEAX = 0;
1326 *aValEBX = 0;
1327 *aValECX = 0;
1328 *aValEDX = 0;
1329#endif
1330
1331 return S_OK;
1332}
1333
1334/**
1335 * Returns the amount of installed system memory in megabytes
1336 *
1337 * @returns COM status code
1338 * @param aSize address of result variable
1339 */
1340HRESULT Host::getMemorySize(ULONG *aSize)
1341{
1342 // no locking required
1343
1344 uint64_t cb;
1345 int rc = RTSystemQueryTotalRam(&cb);
1346 if (RT_FAILURE(rc))
1347 return E_FAIL;
1348 *aSize = (ULONG)(cb / _1M);
1349 return S_OK;
1350}
1351
1352/**
1353 * Returns the current system memory free space in megabytes
1354 *
1355 * @returns COM status code
1356 * @param aAvailable address of result variable
1357 */
1358HRESULT Host::getMemoryAvailable(ULONG *aAvailable)
1359{
1360 // no locking required
1361
1362 uint64_t cb;
1363 int rc = RTSystemQueryAvailableRam(&cb);
1364 if (RT_FAILURE(rc))
1365 return E_FAIL;
1366 *aAvailable = (ULONG)(cb / _1M);
1367 return S_OK;
1368}
1369
1370/**
1371 * Returns the name string of the host operating system
1372 *
1373 * @returns COM status code
1374 * @param aOperatingSystem result variable
1375 */
1376HRESULT Host::getOperatingSystem(com::Utf8Str &aOperatingSystem)
1377{
1378 // no locking required
1379
1380 char szOSName[80];
1381 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szOSName, sizeof(szOSName));
1382 if (RT_FAILURE(vrc))
1383 return E_FAIL; /** @todo error reporting? */
1384 aOperatingSystem = Utf8Str(szOSName);
1385 return S_OK;
1386}
1387
1388/**
1389 * Returns the version string of the host operating system
1390 *
1391 * @returns COM status code
1392 * @param aVersion address of result variable
1393 */
1394HRESULT Host::getOSVersion(com::Utf8Str &aVersion)
1395{
1396 // no locking required
1397
1398 /* Get the OS release. Reserve some buffer space for the service pack. */
1399 char szOSRelease[128];
1400 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSRelease, sizeof(szOSRelease) - 32);
1401 if (RT_FAILURE(vrc))
1402 return E_FAIL; /** @todo error reporting? */
1403
1404 /* Append the service pack if present. */
1405 char szOSServicePack[80];
1406 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szOSServicePack, sizeof(szOSServicePack));
1407 if (RT_FAILURE(vrc))
1408 {
1409 if (vrc != VERR_NOT_SUPPORTED)
1410 return E_FAIL; /** @todo error reporting? */
1411 szOSServicePack[0] = '\0';
1412 }
1413 if (szOSServicePack[0] != '\0')
1414 {
1415 char *psz = strchr(szOSRelease, '\0');
1416 RTStrPrintf(psz, (size_t)(&szOSRelease[sizeof(szOSRelease)] - psz), "sp%s", szOSServicePack);
1417 }
1418
1419 aVersion = szOSRelease;
1420 return S_OK;
1421}
1422
1423/**
1424 * Returns the current host time in milliseconds since 1970-01-01 UTC.
1425 *
1426 * @returns COM status code
1427 * @param aUTCTime address of result variable
1428 */
1429HRESULT Host::getUTCTime(LONG64 *aUTCTime)
1430{
1431 // no locking required
1432
1433 RTTIMESPEC now;
1434 *aUTCTime = RTTimeSpecGetMilli(RTTimeNow(&now));
1435
1436 return S_OK;
1437}
1438
1439
1440HRESULT Host::getAcceleration3DAvailable(BOOL *aSupported)
1441{
1442 HRESULT hrc = S_OK;
1443 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1444 if (m->f3DAccelerationSupported != -1)
1445 *aSupported = m->f3DAccelerationSupported;
1446 else
1447 {
1448 alock.release();
1449
1450#ifdef VBOX_WITH_3D_ACCELERATION
1451 bool fSupported = VBoxOglIs3DAccelerationSupported();
1452#else
1453 bool fSupported = false; /* shoudn't get here, but just in case. */
1454#endif
1455 AutoWriteLock alock2(this COMMA_LOCKVAL_SRC_POS);
1456
1457 m->f3DAccelerationSupported = fSupported;
1458 alock2.release();
1459 *aSupported = fSupported;
1460 }
1461
1462#ifdef DEBUG_misha
1463 AssertMsgFailed(("should not be here any more!\n"));
1464#endif
1465
1466 return hrc;
1467}
1468
1469HRESULT Host::createHostOnlyNetworkInterface(ComPtr<IHostNetworkInterface> &aHostInterface,
1470 ComPtr<IProgress> &aProgress)
1471
1472{
1473#ifdef VBOX_WITH_HOSTNETIF_API
1474 /* No need to lock anything. If there ever will - watch out, the function
1475 * called below grabs the VirtualBox lock. */
1476
1477 int vrc = NetIfCreateHostOnlyNetworkInterface(m->pParent, aHostInterface.asOutParam(), aProgress.asOutParam());
1478 if (RT_SUCCESS(vrc))
1479 {
1480 if (aHostInterface.isNull())
1481 return setError(E_FAIL,
1482 tr("Unable to create a host network interface"));
1483
1484# if !defined(RT_OS_WINDOWS)
1485 Bstr tmpAddr, tmpMask, tmpName;
1486 HRESULT hrc;
1487 hrc = aHostInterface->COMGETTER(Name)(tmpName.asOutParam());
1488 ComAssertComRCRet(hrc, hrc);
1489 hrc = aHostInterface->COMGETTER(IPAddress)(tmpAddr.asOutParam());
1490 ComAssertComRCRet(hrc, hrc);
1491 hrc = aHostInterface->COMGETTER(NetworkMask)(tmpMask.asOutParam());
1492 ComAssertComRCRet(hrc, hrc);
1493 /*
1494 * We need to write the default IP address and mask to extra data now,
1495 * so the interface gets re-created after vboxnetadp.ko reload.
1496 * Note that we avoid calling EnableStaticIpConfig since it would
1497 * change the address on host's interface as well and we want to
1498 * postpone the change until VM actually starts.
1499 */
1500 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress",
1501 tmpName.raw()).raw(),
1502 tmpAddr.raw());
1503 ComAssertComRCRet(hrc, hrc);
1504
1505 hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask",
1506 tmpName.raw()).raw(),
1507 tmpMask.raw());
1508 ComAssertComRCRet(hrc, hrc);
1509# endif /* !defined(RT_OS_WINDOWS) */
1510 }
1511
1512 return S_OK;
1513#else
1514 return E_NOTIMPL;
1515#endif
1516}
1517
1518
1519#ifdef RT_OS_WINDOWS
1520HRESULT Host::i_removePersistentConfig(const Bstr &bstrGuid)
1521{
1522 HRESULT hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/Name", bstrGuid.raw()).raw(), NULL);
1523 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPAddress", bstrGuid.raw()).raw(), NULL);
1524 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPNetMask", bstrGuid.raw()).raw(), NULL);
1525 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPV6Address", bstrGuid.raw()).raw(), NULL);
1526 if (SUCCEEDED(hrc)) hrc = m->pParent->SetExtraData(BstrFmt("HostOnly/{%ls}/IPV6PrefixLen", bstrGuid.raw()).raw(), NULL);
1527 return hrc;
1528}
1529#endif /* RT_OS_WINDOWS */
1530
1531HRESULT Host::removeHostOnlyNetworkInterface(const com::Guid &aId,
1532 ComPtr<IProgress> &aProgress)
1533
1534{
1535#ifdef VBOX_WITH_HOSTNETIF_API
1536 /* No need to lock anything, the code below does not touch the state
1537 * of the host object. If that ever changes then check for lock order
1538 * violations with the called functions. */
1539
1540 Bstr name;
1541 HRESULT rc;
1542
1543 /* first check whether an interface with the given name already exists */
1544 {
1545 ComPtr<IHostNetworkInterface> iface;
1546 rc = findHostNetworkInterfaceById(aId, iface);
1547 if (FAILED(rc))
1548 return setError(VBOX_E_OBJECT_NOT_FOUND,
1549 tr("Host network interface with UUID {%RTuuid} does not exist"),
1550 Guid(aId).raw());
1551 rc = iface->COMGETTER(Name)(name.asOutParam());
1552 ComAssertComRCRet(rc, rc);
1553 }
1554
1555 int r = NetIfRemoveHostOnlyNetworkInterface(m->pParent, aId, aProgress.asOutParam());
1556 if (RT_SUCCESS(r))
1557 {
1558 /* Drop configuration parameters for removed interface */
1559#ifdef RT_OS_WINDOWS
1560 rc = i_removePersistentConfig(Utf8StrFmt("%RTuuid", &aId));
1561 if (FAILED(rc))
1562 LogRel(("i_removePersistentConfig(%RTuuid) failed with 0x%x\n", &aId, rc));
1563#else /* !RT_OS_WINDOWS */
1564 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPAddress", name.raw()).raw(), NULL);
1565 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPNetMask", name.raw()).raw(), NULL);
1566 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6Address", name.raw()).raw(), NULL);
1567 rc = m->pParent->SetExtraData(BstrFmt("HostOnly/%ls/IPV6NetMask", name.raw()).raw(), NULL);
1568#endif /* !RT_OS_WINDOWS */
1569
1570 return S_OK;
1571 }
1572
1573 return r == VERR_NOT_IMPLEMENTED ? E_NOTIMPL : E_FAIL;
1574#else
1575 return E_NOTIMPL;
1576#endif
1577}
1578
1579HRESULT Host::createUSBDeviceFilter(const com::Utf8Str &aName,
1580 ComPtr<IHostUSBDeviceFilter> &aFilter)
1581{
1582#ifdef VBOX_WITH_USB
1583
1584 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1585
1586 ComObjPtr<HostUSBDeviceFilter> filter;
1587 filter.createObject();
1588 HRESULT rc = filter->init(this, Bstr(aName).raw());
1589 ComAssertComRCRet(rc, rc);
1590 rc = filter.queryInterfaceTo(aFilter.asOutParam());
1591 AssertComRCReturn(rc, rc);
1592 return S_OK;
1593#else
1594 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1595 * extended error info to indicate that USB is simply not available
1596 * (w/o treating it as a failure), for example, as in OSE. */
1597 RT_NOREF(aName, aFilter);
1598 ReturnComNotImplemented();
1599#endif
1600}
1601
1602HRESULT Host::insertUSBDeviceFilter(ULONG aPosition,
1603 const ComPtr<IHostUSBDeviceFilter> &aFilter)
1604{
1605#ifdef VBOX_WITH_USB
1606 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1607
1608 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1609
1610 MultiResult rc = i_checkUSBProxyService();
1611 if (FAILED(rc))
1612 return rc;
1613
1614 ComObjPtr<HostUSBDeviceFilter> pFilter;
1615 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
1616 it != m->llChildren.end();
1617 ++it)
1618 {
1619 if (*it == aFilter)
1620 {
1621 pFilter = *it;
1622 break;
1623 }
1624 }
1625 if (pFilter.isNull())
1626 return setError(VBOX_E_INVALID_OBJECT_STATE,
1627 tr("The given USB device filter is not created within this VirtualBox instance"));
1628
1629 if (pFilter->mInList)
1630 return setError(E_INVALIDARG,
1631 tr("The given USB device filter is already in the list"));
1632
1633 /* iterate to the position... */
1634 USBDeviceFilterList::iterator itPos = m->llUSBDeviceFilters.begin();
1635 std::advance(itPos, aPosition);
1636 /* ...and insert */
1637 m->llUSBDeviceFilters.insert(itPos, pFilter);
1638 pFilter->mInList = true;
1639
1640 /* notify the proxy (only when the filter is active) */
1641 if ( m->pUSBProxyService->isActive()
1642 && pFilter->i_getData().mData.fActive)
1643 {
1644 ComAssertRet(pFilter->i_getId() == NULL, E_FAIL);
1645 pFilter->i_getId() = m->pUSBProxyService->insertFilter(&pFilter->i_getData().mUSBFilter);
1646 }
1647
1648 // save the global settings; for that we should hold only the VirtualBox lock
1649 alock.release();
1650 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1651 return rc = m->pParent->i_saveSettings();
1652#else
1653
1654 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1655 * extended error info to indicate that USB is simply not available
1656 * (w/o treating it as a failure), for example, as in OSE. */
1657 RT_NOREF(aPosition, aFilter);
1658 ReturnComNotImplemented();
1659#endif
1660}
1661
1662HRESULT Host::removeUSBDeviceFilter(ULONG aPosition)
1663{
1664#ifdef VBOX_WITH_USB
1665
1666 /* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
1667 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1668
1669 MultiResult rc = i_checkUSBProxyService();
1670 if (FAILED(rc))
1671 return rc;
1672
1673 if (!m->llUSBDeviceFilters.size())
1674 return setError(E_INVALIDARG,
1675 tr("The USB device filter list is empty"));
1676
1677 if (aPosition >= m->llUSBDeviceFilters.size())
1678 return setError(E_INVALIDARG,
1679 tr("Invalid position: %lu (must be in range [0, %lu])"),
1680 aPosition, m->llUSBDeviceFilters.size() - 1);
1681
1682 ComObjPtr<HostUSBDeviceFilter> filter;
1683 {
1684 /* iterate to the position... */
1685 USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin();
1686 std::advance(it, aPosition);
1687 /* ...get an element from there... */
1688 filter = *it;
1689 /* ...and remove */
1690 filter->mInList = false;
1691 m->llUSBDeviceFilters.erase(it);
1692 }
1693
1694 /* notify the proxy (only when the filter is active) */
1695 if (m->pUSBProxyService->isActive() && filter->i_getData().mData.fActive)
1696 {
1697 ComAssertRet(filter->i_getId() != NULL, E_FAIL);
1698 m->pUSBProxyService->removeFilter(filter->i_getId());
1699 filter->i_getId() = NULL;
1700 }
1701
1702 // save the global settings; for that we should hold only the VirtualBox lock
1703 alock.release();
1704 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
1705 return rc = m->pParent->i_saveSettings();
1706#else
1707 /* Note: The GUI depends on this method returning E_NOTIMPL with no
1708 * extended error info to indicate that USB is simply not available
1709 * (w/o treating it as a failure), for example, as in OSE. */
1710 RT_NOREF(aPosition);
1711 ReturnComNotImplemented();
1712#endif
1713}
1714
1715HRESULT Host::findHostDVDDrive(const com::Utf8Str &aName,
1716 ComPtr<IMedium> &aDrive)
1717{
1718 ComObjPtr<Medium> medium;
1719 HRESULT rc = i_findHostDriveByNameOrId(DeviceType_DVD, aName, medium);
1720 if (SUCCEEDED(rc))
1721 rc = medium.queryInterfaceTo(aDrive.asOutParam());
1722 else
1723 rc = setError(rc, tr("The host DVD drive named '%s' could not be found"), aName.c_str());
1724 return rc;
1725}
1726
1727HRESULT Host::findHostFloppyDrive(const com::Utf8Str &aName, ComPtr<IMedium> &aDrive)
1728{
1729 aDrive = NULL;
1730
1731 ComObjPtr<Medium>medium;
1732
1733 HRESULT rc = i_findHostDriveByNameOrId(DeviceType_Floppy, aName, medium);
1734 if (SUCCEEDED(rc))
1735 return medium.queryInterfaceTo(aDrive.asOutParam());
1736 else
1737 return setError(rc, tr("The host floppy drive named '%s' could not be found"), aName.c_str());
1738}
1739
1740HRESULT Host::findHostNetworkInterfaceByName(const com::Utf8Str &aName,
1741 ComPtr<IHostNetworkInterface> &aNetworkInterface)
1742{
1743#ifndef VBOX_WITH_HOSTNETIF_API
1744 return E_NOTIMPL;
1745#else
1746 if (!aName.length())
1747 return E_INVALIDARG;
1748
1749 HRESULT rc = i_updateNetIfList();
1750 if (FAILED(rc))
1751 {
1752 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
1753 return rc;
1754 }
1755#if defined(RT_OS_WINDOWS)
1756 rc = i_updatePersistentConfigForHostOnlyAdapters();
1757 if (FAILED(rc))
1758 {
1759 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
1760 return rc;
1761 }
1762#endif /* defined(RT_OS_WINDOWS) */
1763
1764 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1765
1766 ComObjPtr<HostNetworkInterface> found;
1767 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1768 {
1769 Bstr n;
1770 (*it)->COMGETTER(Name)(n.asOutParam());
1771 if (n == aName)
1772 found = *it;
1773 }
1774
1775 if (!found)
1776 return setError(E_INVALIDARG,
1777 tr("The host network interface named '%s' could not be found"), aName.c_str());
1778
1779 return found.queryInterfaceTo(aNetworkInterface.asOutParam());
1780#endif
1781}
1782
1783HRESULT Host::findHostNetworkInterfaceById(const com::Guid &aId,
1784 ComPtr<IHostNetworkInterface> &aNetworkInterface)
1785{
1786#ifndef VBOX_WITH_HOSTNETIF_API
1787 return E_NOTIMPL;
1788#else
1789 if (!aId.isValid())
1790 return E_INVALIDARG;
1791
1792 HRESULT rc = i_updateNetIfList();
1793 if (FAILED(rc))
1794 {
1795 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
1796 return rc;
1797 }
1798#if defined(RT_OS_WINDOWS)
1799 rc = i_updatePersistentConfigForHostOnlyAdapters();
1800 if (FAILED(rc))
1801 {
1802 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
1803 return rc;
1804 }
1805#endif /* defined(RT_OS_WINDOWS) */
1806
1807 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1808
1809 ComObjPtr<HostNetworkInterface> found;
1810 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1811 {
1812 Bstr g;
1813 (*it)->COMGETTER(Id)(g.asOutParam());
1814 if (Guid(g) == aId)
1815 found = *it;
1816 }
1817
1818 if (!found)
1819 return setError(E_INVALIDARG,
1820 tr("The host network interface with the given GUID could not be found"));
1821 return found.queryInterfaceTo(aNetworkInterface.asOutParam());
1822
1823#endif
1824}
1825
1826HRESULT Host::findHostNetworkInterfacesOfType(HostNetworkInterfaceType_T aType,
1827 std::vector<ComPtr<IHostNetworkInterface> > &aNetworkInterfaces)
1828{
1829#ifdef VBOX_WITH_HOSTNETIF_API
1830 HRESULT rc = i_updateNetIfList();
1831 if (FAILED(rc))
1832 {
1833 Log(("Failed to update host network interface list with rc=%Rhrc\n", rc));
1834 return rc;
1835 }
1836#if defined(RT_OS_WINDOWS)
1837 rc = i_updatePersistentConfigForHostOnlyAdapters();
1838 if (FAILED(rc))
1839 {
1840 LogRel(("Failed to update persistent config for host-only adapters with rc=%Rhrc\n", rc));
1841 return rc;
1842 }
1843#endif /* defined(RT_OS_WINDOWS) */
1844
1845 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1846
1847 HostNetworkInterfaceList resultList;
1848 for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it)
1849 {
1850 HostNetworkInterfaceType_T t;
1851 HRESULT hr = (*it)->COMGETTER(InterfaceType)(&t);
1852 if (FAILED(hr))
1853 return hr;
1854
1855 if (t == aType)
1856 resultList.push_back(*it);
1857 }
1858 aNetworkInterfaces.resize(resultList.size());
1859 size_t i = 0;
1860 for (HostNetworkInterfaceList::iterator it = resultList.begin(); it != resultList.end(); ++it, ++i)
1861 {
1862 (*it).queryInterfaceTo(aNetworkInterfaces[i].asOutParam());
1863 }
1864
1865 return S_OK;
1866#else
1867 return E_NOTIMPL;
1868#endif
1869}
1870
1871HRESULT Host::findUSBDeviceByAddress(const com::Utf8Str &aName,
1872 ComPtr<IHostUSBDevice> &aDevice)
1873{
1874#ifdef VBOX_WITH_USB
1875
1876 aDevice = NULL;
1877 SafeIfaceArray<IHostUSBDevice> devsvec;
1878 HRESULT rc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
1879 if (FAILED(rc))
1880 return rc;
1881
1882 for (size_t i = 0; i < devsvec.size(); ++i)
1883 {
1884 Bstr address;
1885 rc = devsvec[i]->COMGETTER(Address)(address.asOutParam());
1886 if (FAILED(rc))
1887 return rc;
1888 if (address == aName)
1889 {
1890 return (ComPtr<IHostUSBDevice>(devsvec[i]).queryInterfaceTo(aDevice.asOutParam()));
1891 }
1892 }
1893
1894 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1895 tr("Could not find a USB device with address '%s'"),
1896 aName.c_str());
1897
1898#else /* !VBOX_WITH_USB */
1899 RT_NOREF(aName, aDevice);
1900 return E_NOTIMPL;
1901#endif /* !VBOX_WITH_USB */
1902}
1903HRESULT Host::findUSBDeviceById(const com::Guid &aId,
1904 ComPtr<IHostUSBDevice> &aDevice)
1905{
1906#ifdef VBOX_WITH_USB
1907 if (!aId.isValid())
1908 return E_INVALIDARG;
1909
1910 aDevice = NULL;
1911
1912 SafeIfaceArray<IHostUSBDevice> devsvec;
1913 HRESULT rc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
1914 if (FAILED(rc))
1915 return rc;
1916
1917 for (size_t i = 0; i < devsvec.size(); ++i)
1918 {
1919 Bstr id;
1920 rc = devsvec[i]->COMGETTER(Id)(id.asOutParam());
1921 if (FAILED(rc))
1922 return rc;
1923 if (Guid(id) == aId)
1924 {
1925 return (ComPtr<IHostUSBDevice>(devsvec[i]).queryInterfaceTo(aDevice.asOutParam()));
1926 }
1927 }
1928 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
1929 tr("Could not find a USB device with uuid {%RTuuid}"),
1930 aId.raw());
1931
1932#else /* !VBOX_WITH_USB */
1933 RT_NOREF(aId, aDevice);
1934 return E_NOTIMPL;
1935#endif /* !VBOX_WITH_USB */
1936}
1937
1938HRESULT Host::generateMACAddress(com::Utf8Str &aAddress)
1939{
1940 // no locking required
1941 i_generateMACAddress(aAddress);
1942 return S_OK;
1943}
1944
1945/**
1946 * Returns a list of host video capture devices (webcams, etc).
1947 *
1948 * @returns COM status code
1949 * @param aVideoInputDevices Array of interface pointers to be filled.
1950 */
1951HRESULT Host::getVideoInputDevices(std::vector<ComPtr<IHostVideoInputDevice> > &aVideoInputDevices)
1952{
1953 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1954 HostVideoInputDeviceList list;
1955
1956 HRESULT rc = HostVideoInputDevice::queryHostDevices(m->pParent, &list);
1957 if (FAILED(rc))
1958 return rc;
1959
1960 aVideoInputDevices.resize(list.size());
1961 size_t i = 0;
1962 for (HostVideoInputDeviceList::const_iterator it = list.begin(); it != list.end(); ++it, ++i)
1963 (*it).queryInterfaceTo(aVideoInputDevices[i].asOutParam());
1964
1965 return S_OK;
1966}
1967
1968HRESULT Host::addUSBDeviceSource(const com::Utf8Str &aBackend, const com::Utf8Str &aId, const com::Utf8Str &aAddress,
1969 const std::vector<com::Utf8Str> &aPropertyNames, const std::vector<com::Utf8Str> &aPropertyValues)
1970{
1971#ifdef VBOX_WITH_USB
1972 /* The USB proxy service will do the locking. */
1973 return m->pUSBProxyService->addUSBDeviceSource(aBackend, aId, aAddress, aPropertyNames, aPropertyValues);
1974#else
1975 RT_NOREF(aBackend, aId, aAddress, aPropertyNames, aPropertyValues);
1976 ReturnComNotImplemented();
1977#endif
1978}
1979
1980HRESULT Host::removeUSBDeviceSource(const com::Utf8Str &aId)
1981{
1982#ifdef VBOX_WITH_USB
1983 /* The USB proxy service will do the locking. */
1984 return m->pUSBProxyService->removeUSBDeviceSource(aId);
1985#else
1986 RT_NOREF(aId);
1987 ReturnComNotImplemented();
1988#endif
1989}
1990
1991
1992HRESULT Host::getUpdate(ComPtr<IHostUpdate> &aUpdate)
1993{
1994 HRESULT hrc = m->pHostUpdate.queryInterfaceTo(aUpdate.asOutParam());
1995 return hrc;
1996}
1997
1998
1999HRESULT Host::getHostDrives(std::vector<ComPtr<IHostDrive> > &aHostDrives)
2000{
2001 std::list<std::pair<com::Utf8Str, com::Utf8Str> > llDrivesPathsList;
2002 HRESULT hrc = i_getDrivesPathsList(llDrivesPathsList);
2003 if (SUCCEEDED(hrc))
2004 {
2005 for (std::list<std::pair<com::Utf8Str, com::Utf8Str> >::const_iterator it = llDrivesPathsList.begin();
2006 it != llDrivesPathsList.end();
2007 ++it)
2008 {
2009 ComObjPtr<HostDrive> pHostDrive;
2010 hrc = pHostDrive.createObject();
2011 if (SUCCEEDED(hrc))
2012 hrc = pHostDrive->initFromPathAndModel(it->first, it->second);
2013 if (FAILED(hrc))
2014 break;
2015 aHostDrives.push_back(pHostDrive);
2016 }
2017 }
2018 return hrc;
2019}
2020
2021
2022// public methods only for internal purposes
2023////////////////////////////////////////////////////////////////////////////////
2024
2025HRESULT Host::i_loadSettings(const settings::Host &data)
2026{
2027 HRESULT rc = S_OK;
2028#ifdef VBOX_WITH_USB
2029 AutoCaller autoCaller(this);
2030 if (FAILED(autoCaller.rc()))
2031 return autoCaller.rc();
2032
2033 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2034
2035 for (settings::USBDeviceFiltersList::const_iterator it = data.llUSBDeviceFilters.begin();
2036 it != data.llUSBDeviceFilters.end();
2037 ++it)
2038 {
2039 const settings::USBDeviceFilter &f = *it;
2040 ComObjPtr<HostUSBDeviceFilter> pFilter;
2041 pFilter.createObject();
2042 rc = pFilter->init(this, f);
2043 if (FAILED(rc))
2044 break;
2045
2046 m->llUSBDeviceFilters.push_back(pFilter);
2047 pFilter->mInList = true;
2048
2049 /* notify the proxy (only when the filter is active) */
2050 if (pFilter->i_getData().mData.fActive)
2051 {
2052 HostUSBDeviceFilter *flt = pFilter; /* resolve ambiguity */
2053 flt->i_getId() = m->pUSBProxyService->insertFilter(&pFilter->i_getData().mUSBFilter);
2054 }
2055 }
2056
2057 rc = m->pUSBProxyService->i_loadSettings(data.llUSBDeviceSources);
2058#else
2059 RT_NOREF(data);
2060#endif /* VBOX_WITH_USB */
2061 return rc;
2062}
2063
2064HRESULT Host::i_saveSettings(settings::Host &data)
2065{
2066#ifdef VBOX_WITH_USB
2067 AutoCaller autoCaller(this);
2068 if (FAILED(autoCaller.rc()))
2069 return autoCaller.rc();
2070
2071 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2072
2073 data.llUSBDeviceFilters.clear();
2074 data.llUSBDeviceSources.clear();
2075
2076 for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
2077 it != m->llUSBDeviceFilters.end();
2078 ++it)
2079 {
2080 ComObjPtr<HostUSBDeviceFilter> pFilter = *it;
2081 settings::USBDeviceFilter f;
2082 pFilter->i_saveSettings(f);
2083 data.llUSBDeviceFilters.push_back(f);
2084 }
2085
2086 return m->pUSBProxyService->i_saveSettings(data.llUSBDeviceSources);
2087#else
2088 RT_NOREF(data);
2089 return S_OK;
2090#endif /* VBOX_WITH_USB */
2091
2092}
2093
2094/**
2095 * Sets the given pointer to point to the static list of DVD or floppy
2096 * drives in the Host instance data, depending on the @a mediumType
2097 * parameter.
2098 *
2099 * This builds the list on the first call; it adds or removes host drives
2100 * that may have changed if fRefresh == true.
2101 *
2102 * The caller must hold the medium tree write lock before calling this.
2103 * To protect the list to which the caller's pointer points, the caller
2104 * must also hold that lock.
2105 *
2106 * @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
2107 * @param fRefresh Whether to refresh the host drives list even if this is not the first call.
2108 * @param pll Caller's pointer which gets set to the static list of host drives.
2109 * @param treeLock Reference to media tree lock, need to drop it temporarily.
2110 * @returns COM status code
2111 */
2112HRESULT Host::i_getDrives(DeviceType_T mediumType,
2113 bool fRefresh,
2114 MediaList *&pll,
2115 AutoWriteLock &treeLock)
2116{
2117 HRESULT rc = S_OK;
2118 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2119
2120 MediaList llNew;
2121 MediaList *pllCached;
2122 bool *pfListBuilt = NULL;
2123
2124 switch (mediumType)
2125 {
2126 case DeviceType_DVD:
2127 if (!m->fDVDDrivesListBuilt || fRefresh)
2128 {
2129 rc = i_buildDVDDrivesList(llNew);
2130 if (FAILED(rc))
2131 return rc;
2132 pfListBuilt = &m->fDVDDrivesListBuilt;
2133 }
2134 pllCached = &m->llDVDDrives;
2135 break;
2136
2137 case DeviceType_Floppy:
2138 if (!m->fFloppyDrivesListBuilt || fRefresh)
2139 {
2140 rc = i_buildFloppyDrivesList(llNew);
2141 if (FAILED(rc))
2142 return rc;
2143 pfListBuilt = &m->fFloppyDrivesListBuilt;
2144 }
2145 pllCached = &m->llFloppyDrives;
2146 break;
2147
2148 default:
2149 return E_INVALIDARG;
2150 }
2151
2152 if (pfListBuilt)
2153 {
2154 // a list was built in llNew above:
2155 if (!*pfListBuilt)
2156 {
2157 // this was the first call (instance bool is still false): then just copy the whole list and return
2158 *pllCached = llNew;
2159 // and mark the instance data as "built"
2160 *pfListBuilt = true;
2161 }
2162 else
2163 {
2164 // list was built, and this was a subsequent call: then compare the old and the new lists
2165
2166 // remove drives from the cached list which are no longer present
2167 for (MediaList::iterator itCached = pllCached->begin();
2168 itCached != pllCached->end();
2169 /*nothing */)
2170 {
2171 Medium *pCached = *itCached;
2172 const Utf8Str strLocationCached = pCached->i_getLocationFull();
2173 bool fFound = false;
2174 for (MediaList::iterator itNew = llNew.begin();
2175 itNew != llNew.end();
2176 ++itNew)
2177 {
2178 Medium *pNew = *itNew;
2179 const Utf8Str strLocationNew = pNew->i_getLocationFull();
2180 if (strLocationNew == strLocationCached)
2181 {
2182 fFound = true;
2183 break;
2184 }
2185 }
2186 if (!fFound)
2187 {
2188 pCached->uninit();
2189 itCached = pllCached->erase(itCached);
2190 }
2191 else
2192 ++itCached;
2193 }
2194
2195 // add drives to the cached list that are not on there yet
2196 for (MediaList::iterator itNew = llNew.begin();
2197 itNew != llNew.end();
2198 ++itNew)
2199 {
2200 Medium *pNew = *itNew;
2201 const Utf8Str strLocationNew = pNew->i_getLocationFull();
2202 bool fFound = false;
2203 for (MediaList::iterator itCached = pllCached->begin();
2204 itCached != pllCached->end();
2205 ++itCached)
2206 {
2207 Medium *pCached = *itCached;
2208 const Utf8Str strLocationCached = pCached->i_getLocationFull();
2209 if (strLocationNew == strLocationCached)
2210 {
2211 fFound = true;
2212 break;
2213 }
2214 }
2215
2216 if (!fFound)
2217 pllCached->push_back(pNew);
2218 }
2219 }
2220 }
2221
2222 // return cached list to caller
2223 pll = pllCached;
2224
2225 // Make sure the media tree lock is released before llNew is cleared,
2226 // as this usually triggers calls to uninit().
2227 treeLock.release();
2228
2229 llNew.clear();
2230
2231 treeLock.acquire();
2232
2233 return rc;
2234}
2235
2236/**
2237 * Goes through the list of host drives that would be returned by getDrives()
2238 * and looks for a host drive with the given UUID. If found, it sets pMedium
2239 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2240 *
2241 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2242 * @param uuid Medium UUID of host drive to look for.
2243 * @param fRefresh Whether to refresh the host drives list (see getDrives())
2244 * @param pMedium Medium object, if found...
2245 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2246 */
2247HRESULT Host::i_findHostDriveById(DeviceType_T mediumType,
2248 const Guid &uuid,
2249 bool fRefresh,
2250 ComObjPtr<Medium> &pMedium)
2251{
2252 MediaList *pllMedia;
2253
2254 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2255 HRESULT rc = i_getDrives(mediumType, fRefresh, pllMedia, treeLock);
2256 if (SUCCEEDED(rc))
2257 {
2258 for (MediaList::iterator it = pllMedia->begin();
2259 it != pllMedia->end();
2260 ++it)
2261 {
2262 Medium *pThis = *it;
2263 AutoCaller mediumCaller(pThis);
2264 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
2265 if (pThis->i_getId() == uuid)
2266 {
2267 pMedium = pThis;
2268 return S_OK;
2269 }
2270 }
2271 }
2272
2273 return VBOX_E_OBJECT_NOT_FOUND;
2274}
2275
2276/**
2277 * Goes through the list of host drives that would be returned by getDrives()
2278 * and looks for a host drive with the given name. If found, it sets pMedium
2279 * to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2280 *
2281 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2282 * @param strLocationFull Name (path) of host drive to look for.
2283 * @param fRefresh Whether to refresh the host drives list (see getDrives())
2284 * @param pMedium Medium object, if found
2285 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2286 */
2287HRESULT Host::i_findHostDriveByName(DeviceType_T mediumType,
2288 const Utf8Str &strLocationFull,
2289 bool fRefresh,
2290 ComObjPtr<Medium> &pMedium)
2291{
2292 MediaList *pllMedia;
2293
2294 AutoWriteLock treeLock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2295 HRESULT rc = i_getDrives(mediumType, fRefresh, pllMedia, treeLock);
2296 if (SUCCEEDED(rc))
2297 {
2298 for (MediaList::iterator it = pllMedia->begin();
2299 it != pllMedia->end();
2300 ++it)
2301 {
2302 Medium *pThis = *it;
2303 AutoCaller mediumCaller(pThis);
2304 AutoReadLock mediumLock(pThis COMMA_LOCKVAL_SRC_POS);
2305 if (pThis->i_getLocationFull() == strLocationFull)
2306 {
2307 pMedium = pThis;
2308 return S_OK;
2309 }
2310 }
2311 }
2312
2313 return VBOX_E_OBJECT_NOT_FOUND;
2314}
2315
2316/**
2317 * Goes through the list of host drives that would be returned by getDrives()
2318 * and looks for a host drive with the given name, location or ID. If found,
2319 * it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
2320 *
2321 * @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
2322 * @param strNameOrId Name or full location or UUID of host drive to look for.
2323 * @param pMedium Medium object, if found...
2324 * @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
2325 */
2326HRESULT Host::i_findHostDriveByNameOrId(DeviceType_T mediumType,
2327 const Utf8Str &strNameOrId,
2328 ComObjPtr<Medium> &pMedium)
2329{
2330 AutoWriteLock wlock(m->pParent->i_getMediaTreeLockHandle() COMMA_LOCKVAL_SRC_POS);
2331
2332 Guid uuid(strNameOrId);
2333 if (uuid.isValid() && !uuid.isZero())
2334 return i_findHostDriveById(mediumType, uuid, true /* fRefresh */, pMedium);
2335
2336 // string is not a syntactically valid UUID: try a name then
2337 return i_findHostDriveByName(mediumType, strNameOrId, true /* fRefresh */, pMedium);
2338}
2339
2340/**
2341 * Called from getDrives() to build the DVD drives list.
2342 * @param list Media list
2343 * @return
2344 */
2345HRESULT Host::i_buildDVDDrivesList(MediaList &list)
2346{
2347 HRESULT rc = S_OK;
2348
2349 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2350
2351 try
2352 {
2353#if defined(RT_OS_WINDOWS)
2354 int sz = GetLogicalDriveStrings(0, NULL);
2355 TCHAR *hostDrives = new TCHAR[sz+1];
2356 GetLogicalDriveStrings(sz, hostDrives);
2357 wchar_t driveName[3] = { '?', ':', '\0' };
2358 TCHAR *p = hostDrives;
2359 do
2360 {
2361 if (GetDriveType(p) == DRIVE_CDROM)
2362 {
2363 driveName[0] = *p;
2364 ComObjPtr<Medium> hostDVDDriveObj;
2365 hostDVDDriveObj.createObject();
2366 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(driveName));
2367 list.push_back(hostDVDDriveObj);
2368 }
2369 p += _tcslen(p) + 1;
2370 }
2371 while (*p);
2372 delete[] hostDrives;
2373
2374#elif defined(RT_OS_SOLARIS)
2375# ifdef VBOX_USE_LIBHAL
2376 if (!i_getDVDInfoFromHal(list))
2377# endif
2378 {
2379 i_getDVDInfoFromDevTree(list);
2380 }
2381
2382#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
2383 if (RT_SUCCESS(m->hostDrives.updateDVDs()))
2384 for (DriveInfoList::const_iterator it = m->hostDrives.DVDBegin();
2385 SUCCEEDED(rc) && it != m->hostDrives.DVDEnd(); ++it)
2386 {
2387 ComObjPtr<Medium> hostDVDDriveObj;
2388 Utf8Str location(it->mDevice);
2389 Utf8Str description(it->mDescription);
2390 if (SUCCEEDED(rc))
2391 rc = hostDVDDriveObj.createObject();
2392 if (SUCCEEDED(rc))
2393 rc = hostDVDDriveObj->init(m->pParent, DeviceType_DVD, location, description);
2394 if (SUCCEEDED(rc))
2395 list.push_back(hostDVDDriveObj);
2396 }
2397#elif defined(RT_OS_DARWIN)
2398 PDARWINDVD cur = DarwinGetDVDDrives();
2399 while (cur)
2400 {
2401 ComObjPtr<Medium> hostDVDDriveObj;
2402 hostDVDDriveObj.createObject();
2403 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(cur->szName));
2404 list.push_back(hostDVDDriveObj);
2405
2406 /* next */
2407 void *freeMe = cur;
2408 cur = cur->pNext;
2409 RTMemFree(freeMe);
2410 }
2411#else
2412 /* PORTME */
2413#endif
2414 }
2415 catch(std::bad_alloc &)
2416 {
2417 rc = E_OUTOFMEMORY;
2418 }
2419 return rc;
2420}
2421
2422/**
2423 * Called from getDrives() to build the floppy drives list.
2424 * @param list
2425 * @return
2426 */
2427HRESULT Host::i_buildFloppyDrivesList(MediaList &list)
2428{
2429 HRESULT rc = S_OK;
2430
2431 Assert(m->pParent->i_getMediaTreeLockHandle().isWriteLockOnCurrentThread());
2432
2433 try
2434 {
2435#ifdef RT_OS_WINDOWS
2436 int sz = GetLogicalDriveStrings(0, NULL);
2437 TCHAR *hostDrives = new TCHAR[sz+1];
2438 GetLogicalDriveStrings(sz, hostDrives);
2439 wchar_t driveName[3] = { '?', ':', '\0' };
2440 TCHAR *p = hostDrives;
2441 do
2442 {
2443 if (GetDriveType(p) == DRIVE_REMOVABLE)
2444 {
2445 driveName[0] = *p;
2446 ComObjPtr<Medium> hostFloppyDriveObj;
2447 hostFloppyDriveObj.createObject();
2448 hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, Bstr(driveName));
2449 list.push_back(hostFloppyDriveObj);
2450 }
2451 p += _tcslen(p) + 1;
2452 }
2453 while (*p);
2454 delete[] hostDrives;
2455#elif defined(RT_OS_LINUX)
2456 if (RT_SUCCESS(m->hostDrives.updateFloppies()))
2457 for (DriveInfoList::const_iterator it = m->hostDrives.FloppyBegin();
2458 SUCCEEDED(rc) && it != m->hostDrives.FloppyEnd(); ++it)
2459 {
2460 ComObjPtr<Medium> hostFloppyDriveObj;
2461 Utf8Str location(it->mDevice);
2462 Utf8Str description(it->mDescription);
2463 if (SUCCEEDED(rc))
2464 rc = hostFloppyDriveObj.createObject();
2465 if (SUCCEEDED(rc))
2466 rc = hostFloppyDriveObj->init(m->pParent, DeviceType_Floppy, location, description);
2467 if (SUCCEEDED(rc))
2468 list.push_back(hostFloppyDriveObj);
2469 }
2470#else
2471 RT_NOREF(list);
2472 /* PORTME */
2473#endif
2474 }
2475 catch(std::bad_alloc &)
2476 {
2477 rc = E_OUTOFMEMORY;
2478 }
2479
2480 return rc;
2481}
2482
2483#ifdef VBOX_WITH_USB
2484USBProxyService* Host::i_usbProxyService()
2485{
2486 return m->pUSBProxyService;
2487}
2488
2489HRESULT Host::i_addChild(HostUSBDeviceFilter *pChild)
2490{
2491 AutoCaller autoCaller(this);
2492 if (FAILED(autoCaller.rc()))
2493 return autoCaller.rc();
2494
2495 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2496
2497 m->llChildren.push_back(pChild);
2498
2499 return S_OK;
2500}
2501
2502HRESULT Host::i_removeChild(HostUSBDeviceFilter *pChild)
2503{
2504 AutoCaller autoCaller(this);
2505 if (FAILED(autoCaller.rc()))
2506 return autoCaller.rc();
2507
2508 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2509
2510 for (USBDeviceFilterList::iterator it = m->llChildren.begin();
2511 it != m->llChildren.end();
2512 ++it)
2513 {
2514 if (*it == pChild)
2515 {
2516 m->llChildren.erase(it);
2517 break;
2518 }
2519 }
2520
2521 return S_OK;
2522}
2523
2524VirtualBox* Host::i_parent()
2525{
2526 return m->pParent;
2527}
2528
2529/**
2530 * Called by setter methods of all USB device filters.
2531 */
2532HRESULT Host::i_onUSBDeviceFilterChange(HostUSBDeviceFilter *aFilter,
2533 BOOL aActiveChanged /* = FALSE */)
2534{
2535 AutoCaller autoCaller(this);
2536 if (FAILED(autoCaller.rc()))
2537 return autoCaller.rc();
2538
2539 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2540
2541 if (aFilter->mInList)
2542 {
2543 if (aActiveChanged)
2544 {
2545 // insert/remove the filter from the proxy
2546 if (aFilter->i_getData().mData.fActive)
2547 {
2548 ComAssertRet(aFilter->i_getId() == NULL, E_FAIL);
2549 aFilter->i_getId() = m->pUSBProxyService->insertFilter(&aFilter->i_getData().mUSBFilter);
2550 }
2551 else
2552 {
2553 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
2554 m->pUSBProxyService->removeFilter(aFilter->i_getId());
2555 aFilter->i_getId() = NULL;
2556 }
2557 }
2558 else
2559 {
2560 if (aFilter->i_getData().mData.fActive)
2561 {
2562 // update the filter in the proxy
2563 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
2564 m->pUSBProxyService->removeFilter(aFilter->i_getId());
2565 aFilter->i_getId() = m->pUSBProxyService->insertFilter(&aFilter->i_getData().mUSBFilter);
2566 }
2567 }
2568
2569 // save the global settings... yeah, on every single filter property change
2570 // for that we should hold only the VirtualBox lock
2571 alock.release();
2572 AutoWriteLock vboxLock(m->pParent COMMA_LOCKVAL_SRC_POS);
2573 return m->pParent->i_saveSettings();
2574 }
2575
2576 return S_OK;
2577}
2578
2579
2580/**
2581 * Interface for obtaining a copy of the USBDeviceFilterList,
2582 * used by the USBProxyService.
2583 *
2584 * @param aGlobalFilters Where to put the global filter list copy.
2585 * @param aMachines Where to put the machine vector.
2586 */
2587void Host::i_getUSBFilters(Host::USBDeviceFilterList *aGlobalFilters)
2588{
2589 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2590
2591 *aGlobalFilters = m->llUSBDeviceFilters;
2592}
2593
2594#endif /* VBOX_WITH_USB */
2595
2596// private methods
2597////////////////////////////////////////////////////////////////////////////////
2598
2599#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
2600
2601/**
2602 * Helper function to get the slice number from a device path
2603 *
2604 * @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
2605 * @returns Pointer to the slice portion of the given path.
2606 */
2607static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
2608{
2609 char *pszSlice = (char *)strrchr(pszDevLinkPath, 's');
2610 char *pszDisk = (char *)strrchr(pszDevLinkPath, 'd');
2611 char *pszFound;
2612 if (pszSlice && (uintptr_t)pszSlice > (uintptr_t)pszDisk)
2613 pszFound = pszSlice;
2614 else
2615 pszFound = pszDisk;
2616
2617 if (pszFound && RT_C_IS_DIGIT(pszFound[1]))
2618 return pszFound;
2619
2620 return NULL;
2621}
2622
2623/**
2624 * Walk device links and returns an allocated path for the first one in the snapshot.
2625 *
2626 * @param DevLink Handle to the device link being walked.
2627 * @param pvArg Opaque pointer that we use to point to the return
2628 * variable (char *). Caller must call RTStrFree on it.
2629 * @returns DI_WALK_TERMINATE to stop the walk.
2630 */
2631static int solarisWalkDevLink(di_devlink_t DevLink, void *pvArg)
2632{
2633 char **ppszPath = (char **)pvArg;
2634 *ppszPath = RTStrDup(di_devlink_path(DevLink));
2635 return DI_WALK_TERMINATE;
2636}
2637
2638/**
2639 * Walk all devices in the system and enumerate CD/DVD drives.
2640 * @param Node Handle to the current node.
2641 * @param pvArg Opaque data (holds list pointer).
2642 * @returns Solaris specific code whether to continue walking or not.
2643 */
2644static int solarisWalkDeviceNodeForDVD(di_node_t Node, void *pvArg)
2645{
2646 PSOLARISDVD *ppDrives = (PSOLARISDVD *)pvArg;
2647
2648 /*
2649 * Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
2650 * As unfortunately the Solaris drivers only export these common properties.
2651 */
2652 int *pInt = NULL;
2653 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "removable-media", &pInt) >= 0
2654 || di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "hotpluggable", &pInt) >= 0)
2655 {
2656 if (di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2657 && ( *pInt == DTYPE_RODIRECT /* CDROM */
2658 || *pInt == DTYPE_OPTICAL)) /* Optical Drive */
2659 {
2660 char *pszProduct = NULL;
2661 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2662 {
2663 char *pszVendor = NULL;
2664 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2665 {
2666 /*
2667 * Found a DVD drive, we need to scan the minor nodes to find the correct
2668 * slice that represents the whole drive. "s2" is always the whole drive for CD/DVDs.
2669 */
2670 int Major = di_driver_major(Node);
2671 di_minor_t Minor = DI_MINOR_NIL;
2672 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2673 if (DevLink)
2674 {
2675 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2676 {
2677 dev_t Dev = di_minor_devt(Minor);
2678 if ( Major != (int)major(Dev)
2679 || di_minor_spectype(Minor) == S_IFBLK
2680 || di_minor_type(Minor) != DDM_MINOR)
2681 {
2682 continue;
2683 }
2684
2685 char *pszMinorPath = di_devfs_minor_path(Minor);
2686 if (!pszMinorPath)
2687 continue;
2688
2689 char *pszDevLinkPath = NULL;
2690 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2691 di_devfs_path_free(pszMinorPath);
2692
2693 if (pszDevLinkPath)
2694 {
2695 char *pszSlice = solarisGetSliceFromPath(pszDevLinkPath);
2696 if ( pszSlice && !strcmp(pszSlice, "s2")
2697 && !strncmp(pszDevLinkPath, RT_STR_TUPLE("/dev/rdsk"))) /* We want only raw disks */
2698 {
2699 /*
2700 * We've got a fully qualified DVD drive. Add it to the list.
2701 */
2702 PSOLARISDVD pDrive = (PSOLARISDVD)RTMemAllocZ(sizeof(SOLARISDVD));
2703 if (RT_LIKELY(pDrive))
2704 {
2705 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription),
2706 "%s %s", pszVendor, pszProduct);
2707 RTStrPurgeEncoding(pDrive->szDescription);
2708 RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevLinkPath);
2709 if (*ppDrives)
2710 pDrive->pNext = *ppDrives;
2711 *ppDrives = pDrive;
2712
2713 /* We're not interested in any of the other slices, stop minor nodes traversal. */
2714 RTStrFree(pszDevLinkPath);
2715 break;
2716 }
2717 }
2718 RTStrFree(pszDevLinkPath);
2719 }
2720 }
2721 di_devlink_fini(&DevLink);
2722 }
2723 }
2724 }
2725 }
2726 }
2727 return DI_WALK_CONTINUE;
2728}
2729
2730/**
2731 * Solaris specific function to enumerate CD/DVD drives via the device tree.
2732 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2733 */
2734void Host::i_getDVDInfoFromDevTree(std::list<ComObjPtr<Medium> > &list)
2735{
2736 PSOLARISDVD pDrives = NULL;
2737 di_node_t RootNode = di_init("/", DINFOCPYALL);
2738 if (RootNode != DI_NODE_NIL)
2739 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForDVD);
2740
2741 di_fini(RootNode);
2742
2743 while (pDrives)
2744 {
2745 ComObjPtr<Medium> hostDVDDriveObj;
2746 hostDVDDriveObj.createObject();
2747 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
2748 list.push_back(hostDVDDriveObj);
2749
2750 void *pvDrive = pDrives;
2751 pDrives = pDrives->pNext;
2752 RTMemFree(pvDrive);
2753 }
2754}
2755
2756
2757/**
2758 * Walk all devices in the system and enumerate fixed drives.
2759 * @param Node Handle to the current node.
2760 * @param pvArg Opaque data (holds list pointer).
2761 * @returns Solaris specific code whether to continue walking or not.
2762 */
2763static int solarisWalkDeviceNodeForFixedDrive(di_node_t Node, void *pvArg) RT_NOEXCEPT
2764{
2765 PSOLARISFIXEDDISK *ppDrives = (PSOLARISFIXEDDISK *)pvArg;
2766
2767 int *pInt = NULL;
2768 if ( di_prop_lookup_ints(DDI_DEV_T_ANY, Node, "inquiry-device-type", &pInt) > 0
2769 && *pInt == DTYPE_DIRECT) /* Fixed drive */
2770 {
2771 char *pszProduct = NULL;
2772 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-product-id", &pszProduct) > 0)
2773 {
2774 char *pszVendor = NULL;
2775 if (di_prop_lookup_strings(DDI_DEV_T_ANY, Node, "inquiry-vendor-id", &pszVendor) > 0)
2776 {
2777 /*
2778 * Found a fixed drive, we need to scan the minor nodes to find the correct
2779 * slice that represents the whole drive.
2780 */
2781 int Major = di_driver_major(Node);
2782 di_minor_t Minor = DI_MINOR_NIL;
2783 di_devlink_handle_t DevLink = di_devlink_init(NULL /* name */, 0 /* flags */);
2784 if (DevLink)
2785 {
2786 /*
2787 * The device name we have to select depends on drive type. For fixed drives, the
2788 * name without slice or partition should be selected, for USB flash drive the
2789 * partition 0 should be selected and slice 0 for other cases.
2790 */
2791 char *pszDisk = NULL;
2792 char *pszPartition0 = NULL;
2793 char *pszSlice0 = NULL;
2794 while ((Minor = di_minor_next(Node, Minor)) != DI_MINOR_NIL)
2795 {
2796 dev_t Dev = di_minor_devt(Minor);
2797 if ( Major != (int)major(Dev)
2798 || di_minor_spectype(Minor) == S_IFBLK
2799 || di_minor_type(Minor) != DDM_MINOR)
2800 continue;
2801
2802 char *pszMinorPath = di_devfs_minor_path(Minor);
2803 if (!pszMinorPath)
2804 continue;
2805
2806 char *pszDevLinkPath = NULL;
2807 di_devlink_walk(DevLink, NULL, pszMinorPath, DI_PRIMARY_LINK, &pszDevLinkPath, solarisWalkDevLink);
2808 di_devfs_path_free(pszMinorPath);
2809
2810 if (pszDevLinkPath)
2811 {
2812 char const *pszCurSlice = strrchr(pszDevLinkPath, 's');
2813 char const *pszCurDisk = strrchr(pszDevLinkPath, 'd');
2814 char const *pszCurPart = strrchr(pszDevLinkPath, 'p');
2815 char **ppszDst = NULL;
2816 if (pszCurSlice && (uintptr_t)pszCurSlice > (uintptr_t)pszCurDisk && !strcmp(pszCurSlice, "s0"))
2817 ppszDst = &pszSlice0;
2818 else if (pszCurPart && (uintptr_t)pszCurPart > (uintptr_t)pszCurDisk && !strcmp(pszCurPart, "p0"))
2819 ppszDst = &pszPartition0;
2820 else if ( (!pszCurSlice || (uintptr_t)pszCurSlice < (uintptr_t)pszCurDisk)
2821 && (!pszCurPart || (uintptr_t)pszCurPart < (uintptr_t)pszCurDisk)
2822 && *pszDevLinkPath != '\0')
2823 ppszDst = &pszDisk;
2824 else
2825 RTStrFree(pszDevLinkPath);
2826 if (ppszDst)
2827 {
2828 if (*ppszDst != NULL)
2829 RTStrFree(*ppszDst);
2830 *ppszDst = pszDevLinkPath;
2831 }
2832 }
2833 }
2834 di_devlink_fini(&DevLink);
2835 if (pszDisk || pszPartition0 || pszSlice0)
2836 {
2837 PSOLARISFIXEDDISK pDrive = (PSOLARISFIXEDDISK)RTMemAllocZ(sizeof(*pDrive));
2838 if (RT_LIKELY(pDrive))
2839 {
2840 RTStrPrintf(pDrive->szDescription, sizeof(pDrive->szDescription), "%s %s", pszVendor, pszProduct);
2841 RTStrPurgeEncoding(pDrive->szDescription);
2842
2843 const char *pszDevPath = pszDisk ? pszDisk : pszPartition0 ? pszPartition0 : pszSlice0;
2844 int rc = RTStrCopy(pDrive->szRawDiskPath, sizeof(pDrive->szRawDiskPath), pszDevPath);
2845 AssertRC(rc);
2846
2847 if (*ppDrives)
2848 pDrive->pNext = *ppDrives;
2849 *ppDrives = pDrive;
2850 }
2851 RTStrFree(pszDisk);
2852 RTStrFree(pszPartition0);
2853 RTStrFree(pszSlice0);
2854 }
2855 }
2856 }
2857 }
2858 }
2859 return DI_WALK_CONTINUE;
2860}
2861
2862
2863/**
2864 * Solaris specific function to enumerate fixed drives via the device tree.
2865 * Works on Solaris 10 as well as OpenSolaris without depending on libhal.
2866 *
2867 * @returns COM status, either S_OK or E_OUTOFMEMORY.
2868 * @param list Reference to list where the the path/model pairs are to
2869 * be returned.
2870 */
2871HRESULT Host::i_getFixedDrivesFromDevTree(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &list) RT_NOEXCEPT
2872{
2873 PSOLARISFIXEDDISK pDrives = NULL;
2874 di_node_t RootNode = di_init("/", DINFOCPYALL);
2875 if (RootNode != DI_NODE_NIL)
2876 di_walk_node(RootNode, DI_WALK_CLDFIRST, &pDrives, solarisWalkDeviceNodeForFixedDrive);
2877 di_fini(RootNode);
2878
2879 HRESULT hrc = S_OK;
2880 try
2881 {
2882 for (PSOLARISFIXEDDISK pCurDrv = pDrives; pCurDrv; pCurDrv = pCurDrv->pNext)
2883 list.push_back(std::pair<com::Utf8Str, com::Utf8Str>(pCurDrv->szRawDiskPath, pCurDrv->szDescription));
2884 }
2885 catch (std::bad_alloc &)
2886 {
2887 LogRelFunc(("Out of memory!\n"));
2888 list.clear();
2889 hrc = E_OUTOFMEMORY;
2890 }
2891
2892 while (pDrives)
2893 {
2894 PSOLARISFIXEDDISK pFreeMe = pDrives;
2895 pDrives = pDrives->pNext;
2896 ASMCompilerBarrier();
2897 RTMemFree(pFreeMe);
2898 }
2899
2900 return hrc;
2901}
2902
2903
2904/* Solaris hosts, loading libhal at runtime */
2905
2906/**
2907 * Helper function to query the hal subsystem for information about DVD drives attached to the
2908 * system.
2909 *
2910 * @returns true if information was successfully obtained, false otherwise
2911 * @param list Reference to list where the DVDs drives are to be returned.
2912 */
2913bool Host::i_getDVDInfoFromHal(std::list<ComObjPtr<Medium> > &list)
2914{
2915 bool halSuccess = false;
2916 DBusError dbusError;
2917 if (!gLibHalCheckPresence())
2918 return false;
2919 gDBusErrorInit(&dbusError);
2920 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
2921 if (dbusConnection != 0)
2922 {
2923 LibHalContext *halContext = gLibHalCtxNew();
2924 if (halContext != 0)
2925 {
2926 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
2927 {
2928 if (gLibHalCtxInit(halContext, &dbusError))
2929 {
2930 int numDevices;
2931 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
2932 "storage.drive_type", "cdrom",
2933 &numDevices, &dbusError);
2934 if (halDevices != 0)
2935 {
2936 /* Hal is installed and working, so if no devices are reported, assume
2937 that there are none. */
2938 halSuccess = true;
2939 for (int i = 0; i < numDevices; i++)
2940 {
2941 char *devNode = gLibHalDeviceGetPropertyString(halContext,
2942 halDevices[i], "block.device", &dbusError);
2943#ifdef RT_OS_SOLARIS
2944 /* The CD/DVD ioctls work only for raw device nodes. */
2945 char *tmp = getfullrawname(devNode);
2946 gLibHalFreeString(devNode);
2947 devNode = tmp;
2948#endif
2949
2950 if (devNode != 0)
2951 {
2952// if (validateDevice(devNode, true))
2953// {
2954 Utf8Str description;
2955 char *vendor, *product;
2956 /* We do not check the error here, as this field may
2957 not even exist. */
2958 vendor = gLibHalDeviceGetPropertyString(halContext,
2959 halDevices[i], "info.vendor", 0);
2960 product = gLibHalDeviceGetPropertyString(halContext,
2961 halDevices[i], "info.product", &dbusError);
2962 if ((product != 0 && product[0] != 0))
2963 {
2964 if ((vendor != 0) && (vendor[0] != 0))
2965 {
2966 description = Utf8StrFmt("%s %s",
2967 vendor, product);
2968 }
2969 else
2970 {
2971 description = product;
2972 }
2973 ComObjPtr<Medium> hostDVDDriveObj;
2974 hostDVDDriveObj.createObject();
2975 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2976 Bstr(devNode), Bstr(description));
2977 list.push_back(hostDVDDriveObj);
2978 }
2979 else
2980 {
2981 if (product == 0)
2982 {
2983 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
2984 halDevices[i], dbusError.name, dbusError.message));
2985 gDBusErrorFree(&dbusError);
2986 }
2987 ComObjPtr<Medium> hostDVDDriveObj;
2988 hostDVDDriveObj.createObject();
2989 hostDVDDriveObj->init(m->pParent, DeviceType_DVD,
2990 Bstr(devNode));
2991 list.push_back(hostDVDDriveObj);
2992 }
2993 if (vendor != 0)
2994 {
2995 gLibHalFreeString(vendor);
2996 }
2997 if (product != 0)
2998 {
2999 gLibHalFreeString(product);
3000 }
3001// }
3002// else
3003// {
3004// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
3005// }
3006#ifndef RT_OS_SOLARIS
3007 gLibHalFreeString(devNode);
3008#else
3009 free(devNode);
3010#endif
3011 }
3012 else
3013 {
3014 LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
3015 halDevices[i], dbusError.name, dbusError.message));
3016 gDBusErrorFree(&dbusError);
3017 }
3018 }
3019 gLibHalFreeStringArray(halDevices);
3020 }
3021 else
3022 {
3023 LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
3024 gDBusErrorFree(&dbusError);
3025 }
3026 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
3027 {
3028 LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
3029 dbusError.name, dbusError.message));
3030 gDBusErrorFree(&dbusError);
3031 }
3032 }
3033 else
3034 {
3035 LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
3036 dbusError.name, dbusError.message));
3037 gDBusErrorFree(&dbusError);
3038 }
3039 gLibHalCtxFree(halContext);
3040 }
3041 else
3042 {
3043 LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
3044 }
3045 }
3046 else
3047 {
3048 LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
3049 }
3050 gDBusConnectionUnref(dbusConnection);
3051 }
3052 else
3053 {
3054 LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3055 dbusError.name, dbusError.message));
3056 gDBusErrorFree(&dbusError);
3057 }
3058 return halSuccess;
3059}
3060
3061
3062/**
3063 * Helper function to query the hal subsystem for information about floppy drives attached to the
3064 * system.
3065 *
3066 * @returns true if information was successfully obtained, false otherwise
3067 * @retval list drives found will be attached to this list
3068 */
3069bool Host::i_getFloppyInfoFromHal(std::list< ComObjPtr<Medium> > &list)
3070{
3071 bool halSuccess = false;
3072 DBusError dbusError;
3073 if (!gLibHalCheckPresence())
3074 return false;
3075 gDBusErrorInit(&dbusError);
3076 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
3077 if (dbusConnection != 0)
3078 {
3079 LibHalContext *halContext = gLibHalCtxNew();
3080 if (halContext != 0)
3081 {
3082 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
3083 {
3084 if (gLibHalCtxInit(halContext, &dbusError))
3085 {
3086 int numDevices;
3087 char **halDevices = gLibHalFindDeviceStringMatch(halContext,
3088 "storage.drive_type", "floppy",
3089 &numDevices, &dbusError);
3090 if (halDevices != 0)
3091 {
3092 /* Hal is installed and working, so if no devices are reported, assume
3093 that there are none. */
3094 halSuccess = true;
3095 for (int i = 0; i < numDevices; i++)
3096 {
3097 char *driveType = gLibHalDeviceGetPropertyString(halContext,
3098 halDevices[i], "storage.drive_type", 0);
3099 if (driveType != 0)
3100 {
3101 if (strcmp(driveType, "floppy") != 0)
3102 {
3103 gLibHalFreeString(driveType);
3104 continue;
3105 }
3106 gLibHalFreeString(driveType);
3107 }
3108 else
3109 {
3110 /* An error occurred. The attribute "storage.drive_type"
3111 probably didn't exist. */
3112 continue;
3113 }
3114 char *devNode = gLibHalDeviceGetPropertyString(halContext,
3115 halDevices[i], "block.device", &dbusError);
3116 if (devNode != 0)
3117 {
3118// if (validateDevice(devNode, false))
3119// {
3120 Utf8Str description;
3121 char *vendor, *product;
3122 /* We do not check the error here, as this field may
3123 not even exist. */
3124 vendor = gLibHalDeviceGetPropertyString(halContext,
3125 halDevices[i], "info.vendor", 0);
3126 product = gLibHalDeviceGetPropertyString(halContext,
3127 halDevices[i], "info.product", &dbusError);
3128 if ((product != 0) && (product[0] != 0))
3129 {
3130 if ((vendor != 0) && (vendor[0] != 0))
3131 {
3132 description = Utf8StrFmt("%s %s",
3133 vendor, product);
3134 }
3135 else
3136 {
3137 description = product;
3138 }
3139 ComObjPtr<Medium> hostFloppyDrive;
3140 hostFloppyDrive.createObject();
3141 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
3142 Bstr(devNode), Bstr(description));
3143 list.push_back(hostFloppyDrive);
3144 }
3145 else
3146 {
3147 if (product == 0)
3148 {
3149 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
3150 halDevices[i], dbusError.name, dbusError.message));
3151 gDBusErrorFree(&dbusError);
3152 }
3153 ComObjPtr<Medium> hostFloppyDrive;
3154 hostFloppyDrive.createObject();
3155 hostFloppyDrive->init(m->pParent, DeviceType_DVD,
3156 Bstr(devNode));
3157 list.push_back(hostFloppyDrive);
3158 }
3159 if (vendor != 0)
3160 {
3161 gLibHalFreeString(vendor);
3162 }
3163 if (product != 0)
3164 {
3165 gLibHalFreeString(product);
3166 }
3167// }
3168// else
3169// {
3170// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
3171// }
3172 gLibHalFreeString(devNode);
3173 }
3174 else
3175 {
3176 LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
3177 halDevices[i], dbusError.name, dbusError.message));
3178 gDBusErrorFree(&dbusError);
3179 }
3180 }
3181 gLibHalFreeStringArray(halDevices);
3182 }
3183 else
3184 {
3185 LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
3186 gDBusErrorFree(&dbusError);
3187 }
3188 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
3189 {
3190 LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
3191 dbusError.name, dbusError.message));
3192 gDBusErrorFree(&dbusError);
3193 }
3194 }
3195 else
3196 {
3197 LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
3198 dbusError.name, dbusError.message));
3199 gDBusErrorFree(&dbusError);
3200 }
3201 gLibHalCtxFree(halContext);
3202 }
3203 else
3204 {
3205 LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
3206 }
3207 }
3208 else
3209 {
3210 LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
3211 }
3212 gDBusConnectionUnref(dbusConnection);
3213 }
3214 else
3215 {
3216 LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3217 dbusError.name, dbusError.message));
3218 gDBusErrorFree(&dbusError);
3219 }
3220 return halSuccess;
3221}
3222
3223
3224/**
3225 * Helper function to query the hal subsystem for information about fixed drives attached to the
3226 * system.
3227 *
3228 * @returns COM status code. (setError is not called on failure as we only fail
3229 * with E_OUTOFMEMORY.)
3230 * @retval S_OK on success.
3231 * @retval S_FALSE if HAL cannot be used.
3232 * @param list Reference to list to return the path/model string pairs.
3233 */
3234HRESULT Host::i_getFixedDrivesFromHal(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &list) RT_NOEXCEPT
3235{
3236 HRESULT hrc = S_FALSE;
3237 if (!gLibHalCheckPresence())
3238 return hrc;
3239
3240 DBusError dbusError;
3241 gDBusErrorInit(&dbusError);
3242 DBusConnection *dbusConnection = gDBusBusGet(DBUS_BUS_SYSTEM, &dbusError);
3243 if (dbusConnection != 0)
3244 {
3245 LibHalContext *halContext = gLibHalCtxNew();
3246 if (halContext != 0)
3247 {
3248 if (gLibHalCtxSetDBusConnection(halContext, dbusConnection))
3249 {
3250 if (gLibHalCtxInit(halContext, &dbusError))
3251 {
3252 int cDevices;
3253 char **halDevices = gLibHalFindDeviceStringMatch(halContext, "storage.drive_type", "disk",
3254 &cDevices, &dbusError);
3255 if (halDevices != 0)
3256 {
3257 /* Hal is installed and working, so if no devices are reported, assume
3258 that there are none. */
3259 hrc = S_OK;
3260 for (int i = 0; i < cDevices && hrc == S_OK; i++)
3261 {
3262 char *pszDevNode = gLibHalDeviceGetPropertyString(halContext, halDevices[i], "block.device",
3263 &dbusError);
3264 /* The fixed drive ioctls work only for raw device nodes. */
3265 char *pszTmp = getfullrawname(pszDevNode);
3266 gLibHalFreeString(pszDevNode);
3267 pszDevNode = pszTmp;
3268 if (pszDevNode != 0)
3269 {
3270 /* We do not check the error here, as this field may
3271 not even exist. */
3272 char *pszVendor = gLibHalDeviceGetPropertyString(halContext, halDevices[i], "info.vendor", 0);
3273 char *pszProduct = gLibHalDeviceGetPropertyString(halContext, halDevices[i], "info.product",
3274 &dbusError);
3275 Utf8Str strDescription;
3276 if (pszProduct != NULL && pszProduct[0] != '\0')
3277 {
3278 int vrc;
3279 if (pszVendor != NULL && pszVendor[0] != '\0')
3280 vrc = strDescription.printfNoThrow("%s %s", pszVendor, pszProduct);
3281 else
3282 vrc = strDescription.assignNoThrow(pszProduct);
3283 AssertRCStmt(vrc, hrc = E_OUTOFMEMORY);
3284 }
3285 if (pszVendor != NULL)
3286 gLibHalFreeString(pszVendor);
3287 if (pszProduct != NULL)
3288 gLibHalFreeString(pszProduct);
3289
3290 /* Correct device/partition/slice already choosen. Just add it to the return list */
3291 if (hrc == S_OK)
3292 try
3293 {
3294 list.push_back(std::pair<com::Utf8Str, com::Utf8Str>(pszDevNode, strDescription));
3295 }
3296 catch (std::bad_alloc &)
3297 {
3298 AssertFailedStmt(hrc = E_OUTOFMEMORY);
3299 }
3300 gLibHalFreeString(pszDevNode);
3301 }
3302 else
3303 {
3304 LogRel(("Host::COMGETTER(HostDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
3305 halDevices[i], dbusError.name, dbusError.message));
3306 gDBusErrorFree(&dbusError);
3307 }
3308 }
3309 gLibHalFreeStringArray(halDevices);
3310 }
3311 else
3312 {
3313 LogRel(("Host::COMGETTER(HostDrives): failed to get devices with capability \"storage.disk\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
3314 gDBusErrorFree(&dbusError);
3315 }
3316 if (!gLibHalCtxShutdown(halContext, &dbusError)) /* what now? */
3317 {
3318 LogRel(("Host::COMGETTER(HostDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n",
3319 dbusError.name, dbusError.message));
3320 gDBusErrorFree(&dbusError);
3321 }
3322 }
3323 else
3324 {
3325 LogRel(("Host::COMGETTER(HostDrives): failed to initialise libhal context. dbus error: %s (%s)\n",
3326 dbusError.name, dbusError.message));
3327 gDBusErrorFree(&dbusError);
3328 }
3329 gLibHalCtxFree(halContext);
3330 }
3331 else
3332 LogRel(("Host::COMGETTER(HostDrives): failed to set libhal connection to dbus.\n"));
3333 }
3334 else
3335 LogRel(("Host::COMGETTER(HostDrives): failed to get a libhal context - out of memory?\n"));
3336 gDBusConnectionUnref(dbusConnection);
3337 }
3338 else
3339 {
3340 LogRel(("Host::COMGETTER(HostDrives): failed to connect to dbus. dbus error: %s (%s)\n",
3341 dbusError.name, dbusError.message));
3342 gDBusErrorFree(&dbusError);
3343 }
3344 return hrc;
3345}
3346
3347#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
3348
3349/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
3350#if defined(RT_OS_SOLARIS)
3351
3352/**
3353 * Helper function to parse the given mount file and add found entries
3354 */
3355void Host::i_parseMountTable(char *mountTable, std::list< ComObjPtr<Medium> > &list)
3356{
3357#ifdef RT_OS_LINUX
3358 FILE *mtab = setmntent(mountTable, "r");
3359 if (mtab)
3360 {
3361 struct mntent *mntent;
3362 char *mnt_type;
3363 char *mnt_dev;
3364 char *tmp;
3365 while ((mntent = getmntent(mtab)))
3366 {
3367 mnt_type = (char*)malloc(strlen(mntent->mnt_type) + 1);
3368 mnt_dev = (char*)malloc(strlen(mntent->mnt_fsname) + 1);
3369 strcpy(mnt_type, mntent->mnt_type);
3370 strcpy(mnt_dev, mntent->mnt_fsname);
3371 // supermount fs case
3372 if (strcmp(mnt_type, "supermount") == 0)
3373 {
3374 tmp = strstr(mntent->mnt_opts, "fs=");
3375 if (tmp)
3376 {
3377 free(mnt_type);
3378 mnt_type = strdup(tmp + strlen("fs="));
3379 if (mnt_type)
3380 {
3381 tmp = strchr(mnt_type, ',');
3382 if (tmp)
3383 *tmp = '\0';
3384 }
3385 }
3386 tmp = strstr(mntent->mnt_opts, "dev=");
3387 if (tmp)
3388 {
3389 free(mnt_dev);
3390 mnt_dev = strdup(tmp + strlen("dev="));
3391 if (mnt_dev)
3392 {
3393 tmp = strchr(mnt_dev, ',');
3394 if (tmp)
3395 *tmp = '\0';
3396 }
3397 }
3398 }
3399 // use strstr here to cover things fs types like "udf,iso9660"
3400 if (strstr(mnt_type, "iso9660") == 0)
3401 {
3402 /** @todo check whether we've already got the drive in our list! */
3403 if (i_validateDevice(mnt_dev, true))
3404 {
3405 ComObjPtr<Medium> hostDVDDriveObj;
3406 hostDVDDriveObj.createObject();
3407 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(mnt_dev));
3408 list.push_back (hostDVDDriveObj);
3409 }
3410 }
3411 free(mnt_dev);
3412 free(mnt_type);
3413 }
3414 endmntent(mtab);
3415 }
3416#else // RT_OS_SOLARIS
3417 FILE *mntFile = fopen(mountTable, "r");
3418 if (mntFile)
3419 {
3420 struct mnttab mntTab;
3421 while (getmntent(mntFile, &mntTab) == 0)
3422 {
3423 const char *mountName = mntTab.mnt_special;
3424 const char *mountPoint = mntTab.mnt_mountp;
3425 const char *mountFSType = mntTab.mnt_fstype;
3426 if (mountName && mountPoint && mountFSType)
3427 {
3428 // skip devices we are not interested in
3429 if ((*mountName && mountName[0] == '/') && // skip 'fake' devices (like -hosts,
3430 // proc, fd, swap)
3431 (*mountFSType && (strncmp(mountFSType, RT_STR_TUPLE("devfs")) != 0 && // skip devfs
3432 // (i.e. /devices)
3433 strncmp(mountFSType, RT_STR_TUPLE("dev")) != 0 && // skip dev (i.e. /dev)
3434 strncmp(mountFSType, RT_STR_TUPLE("lofs")) != 0))) // skip loop-back file-system (lofs)
3435 {
3436 char *rawDevName = getfullrawname((char *)mountName);
3437 if (i_validateDevice(rawDevName, true))
3438 {
3439 ComObjPtr<Medium> hostDVDDriveObj;
3440 hostDVDDriveObj.createObject();
3441 hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(rawDevName));
3442 list.push_back(hostDVDDriveObj);
3443 }
3444 free(rawDevName);
3445 }
3446 }
3447 }
3448
3449 fclose(mntFile);
3450 }
3451#endif
3452}
3453
3454/**
3455 * Helper function to check whether the given device node is a valid drive
3456 */
3457bool Host::i_validateDevice(const char *deviceNode, bool isCDROM)
3458{
3459 struct stat statInfo;
3460 bool retValue = false;
3461
3462 // sanity check
3463 if (!deviceNode)
3464 {
3465 return false;
3466 }
3467
3468 // first a simple stat() call
3469 if (stat(deviceNode, &statInfo) < 0)
3470 {
3471 return false;
3472 }
3473 else
3474 {
3475 if (isCDROM)
3476 {
3477 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
3478 {
3479 int fileHandle;
3480 // now try to open the device
3481 fileHandle = open(deviceNode, O_RDONLY | O_NONBLOCK, 0);
3482 if (fileHandle >= 0)
3483 {
3484 cdrom_subchnl cdChannelInfo;
3485 cdChannelInfo.cdsc_format = CDROM_MSF;
3486 // this call will finally reveal the whole truth
3487#ifdef RT_OS_LINUX
3488 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
3489 (errno == EIO) || (errno == ENOENT) ||
3490 (errno == EINVAL) || (errno == ENOMEDIUM))
3491#else
3492 if ((ioctl(fileHandle, CDROMSUBCHNL, &cdChannelInfo) == 0) ||
3493 (errno == EIO) || (errno == ENOENT) ||
3494 (errno == EINVAL))
3495#endif
3496 {
3497 retValue = true;
3498 }
3499 close(fileHandle);
3500 }
3501 }
3502 } else
3503 {
3504 // floppy case
3505 if (S_ISCHR(statInfo.st_mode) || S_ISBLK(statInfo.st_mode))
3506 {
3507 /// @todo do some more testing, maybe a nice IOCTL!
3508 retValue = true;
3509 }
3510 }
3511 }
3512 return retValue;
3513}
3514#endif // RT_OS_SOLARIS
3515
3516#ifdef VBOX_WITH_USB
3517/**
3518 * Checks for the presence and status of the USB Proxy Service.
3519 * Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
3520 * warning) if the proxy service is not available due to the way the host is
3521 * configured (at present, that means that usbfs and hal/DBus are not
3522 * available on a Linux host) or E_FAIL and a corresponding error message
3523 * otherwise. Intended to be used by methods that rely on the Proxy Service
3524 * availability.
3525 *
3526 * @note This method may return a warning result code. It is recommended to use
3527 * MultiError to store the return value.
3528 *
3529 * @note Locks this object for reading.
3530 */
3531HRESULT Host::i_checkUSBProxyService()
3532{
3533 AutoCaller autoCaller(this);
3534 if (FAILED(autoCaller.rc()))
3535 return autoCaller.rc();
3536
3537 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3538
3539 AssertReturn(m->pUSBProxyService, E_FAIL);
3540 if (!m->pUSBProxyService->isActive())
3541 {
3542 /* disable the USB controller completely to avoid assertions if the
3543 * USB proxy service could not start. */
3544
3545 switch (m->pUSBProxyService->getLastError())
3546 {
3547 case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
3548 return setWarning(E_FAIL,
3549 tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
3550 case VERR_VUSB_USB_DEVICE_PERMISSION:
3551 return setWarning(E_FAIL,
3552 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"));
3553 case VERR_VUSB_USBFS_PERMISSION:
3554 return setWarning(E_FAIL,
3555 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"));
3556 case VINF_SUCCESS:
3557 return setWarning(E_FAIL,
3558 tr("The USB Proxy Service has not yet been ported to this host"));
3559 default:
3560 return setWarning(E_FAIL, "%s: %Rrc",
3561 tr("Could not load the Host USB Proxy service"),
3562 m->pUSBProxyService->getLastError());
3563 }
3564 }
3565
3566 return S_OK;
3567}
3568#endif /* VBOX_WITH_USB */
3569
3570HRESULT Host::i_updateNetIfList()
3571{
3572#ifdef VBOX_WITH_HOSTNETIF_API
3573 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
3574
3575 /** @todo r=klaus it would save lots of clock cycles if for concurrent
3576 * threads executing this code we'd only do one interface enumeration
3577 * and update, and let the other threads use the result as is. However
3578 * if there's a constant hammering of this method, we don't want this
3579 * to cause update starvation. */
3580 HostNetworkInterfaceList list;
3581 int rc = NetIfList(list);
3582 if (rc)
3583 {
3584 Log(("Failed to get host network interface list with rc=%Rrc\n", rc));
3585 return E_FAIL;
3586 }
3587
3588 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3589
3590 AssertReturn(m->pParent, E_FAIL);
3591 /* Make a copy as the original may be partially destroyed later. */
3592 HostNetworkInterfaceList listCopy(list);
3593 HostNetworkInterfaceList::iterator itOld, itNew;
3594# ifdef VBOX_WITH_RESOURCE_USAGE_API
3595 PerformanceCollector *aCollector = m->pParent->i_performanceCollector();
3596# endif
3597 for (itOld = m->llNetIfs.begin(); itOld != m->llNetIfs.end(); ++itOld)
3598 {
3599 bool fGone = true;
3600 Bstr nameOld;
3601 (*itOld)->COMGETTER(Name)(nameOld.asOutParam());
3602 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
3603 {
3604 Bstr nameNew;
3605 (*itNew)->COMGETTER(Name)(nameNew.asOutParam());
3606 if (nameNew == nameOld)
3607 {
3608 fGone = false;
3609 (*itNew)->uninit();
3610 listCopy.erase(itNew);
3611 break;
3612 }
3613 }
3614 if (fGone)
3615 {
3616# ifdef VBOX_WITH_RESOURCE_USAGE_API
3617 (*itOld)->i_unregisterMetrics(aCollector, this);
3618 (*itOld)->uninit();
3619# endif
3620 }
3621 }
3622 /*
3623 * Need to set the references to VirtualBox object in all interface objects
3624 * (see @bugref{6439}).
3625 */
3626 for (itNew = list.begin(); itNew != list.end(); ++itNew)
3627 (*itNew)->i_setVirtualBox(m->pParent);
3628 /* At this point listCopy will contain newly discovered interfaces only. */
3629 for (itNew = listCopy.begin(); itNew != listCopy.end(); ++itNew)
3630 {
3631 HostNetworkInterfaceType_T t;
3632 HRESULT hrc = (*itNew)->COMGETTER(InterfaceType)(&t);
3633 if (FAILED(hrc))
3634 {
3635 Bstr n;
3636 (*itNew)->COMGETTER(Name)(n.asOutParam());
3637 LogRel(("Host::updateNetIfList: failed to get interface type for %ls\n", n.raw()));
3638 }
3639 else if (t == HostNetworkInterfaceType_Bridged)
3640 {
3641# ifdef VBOX_WITH_RESOURCE_USAGE_API
3642 (*itNew)->i_registerMetrics(aCollector, this);
3643# endif
3644 }
3645 }
3646 m->llNetIfs = list;
3647 return S_OK;
3648#else
3649 return E_NOTIMPL;
3650#endif
3651}
3652
3653#ifdef VBOX_WITH_RESOURCE_USAGE_API
3654
3655void Host::i_registerDiskMetrics(PerformanceCollector *aCollector)
3656{
3657 pm::CollectorHAL *hal = aCollector->getHAL();
3658 /* Create sub metrics */
3659 Utf8StrFmt fsNameBase("FS/{%s}/Usage", "/");
3660 //Utf8StrFmt fsNameBase("Filesystem/[root]/Usage");
3661 pm::SubMetric *fsRootUsageTotal = new pm::SubMetric(fsNameBase + "/Total",
3662 "Root file system size.");
3663 pm::SubMetric *fsRootUsageUsed = new pm::SubMetric(fsNameBase + "/Used",
3664 "Root file system space currently occupied.");
3665 pm::SubMetric *fsRootUsageFree = new pm::SubMetric(fsNameBase + "/Free",
3666 "Root file system space currently empty.");
3667
3668 pm::BaseMetric *fsRootUsage = new pm::HostFilesystemUsage(hal, this,
3669 fsNameBase, "/",
3670 fsRootUsageTotal,
3671 fsRootUsageUsed,
3672 fsRootUsageFree);
3673 aCollector->registerBaseMetric(fsRootUsage);
3674
3675 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal, 0));
3676 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3677 new pm::AggregateAvg()));
3678 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3679 new pm::AggregateMin()));
3680 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageTotal,
3681 new pm::AggregateMax()));
3682
3683 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed, 0));
3684 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3685 new pm::AggregateAvg()));
3686 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3687 new pm::AggregateMin()));
3688 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageUsed,
3689 new pm::AggregateMax()));
3690
3691 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree, 0));
3692 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3693 new pm::AggregateAvg()));
3694 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3695 new pm::AggregateMin()));
3696 aCollector->registerMetric(new pm::Metric(fsRootUsage, fsRootUsageFree,
3697 new pm::AggregateMax()));
3698
3699 /* For now we are concerned with the root file system only. */
3700 pm::DiskList disksUsage, disksLoad;
3701 int rc = hal->getDiskListByFs("/", disksUsage, disksLoad);
3702 if (RT_FAILURE(rc))
3703 return;
3704 pm::DiskList::iterator it;
3705 for (it = disksLoad.begin(); it != disksLoad.end(); ++it)
3706 {
3707 Utf8StrFmt strName("Disk/%s", it->c_str());
3708 pm::SubMetric *fsLoadUtil = new pm::SubMetric(strName + "/Load/Util",
3709 "Percentage of time disk was busy serving I/O requests.");
3710 pm::BaseMetric *fsLoad = new pm::HostDiskLoadRaw(hal, this, strName + "/Load",
3711 *it, fsLoadUtil);
3712 aCollector->registerBaseMetric(fsLoad);
3713
3714 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil, 0));
3715 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3716 new pm::AggregateAvg()));
3717 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3718 new pm::AggregateMin()));
3719 aCollector->registerMetric(new pm::Metric(fsLoad, fsLoadUtil,
3720 new pm::AggregateMax()));
3721 }
3722 for (it = disksUsage.begin(); it != disksUsage.end(); ++it)
3723 {
3724 Utf8StrFmt strName("Disk/%s", it->c_str());
3725 pm::SubMetric *fsUsageTotal = new pm::SubMetric(strName + "/Usage/Total",
3726 "Disk size.");
3727 pm::BaseMetric *fsUsage = new pm::HostDiskUsage(hal, this, strName + "/Usage",
3728 *it, fsUsageTotal);
3729 aCollector->registerBaseMetric(fsUsage);
3730
3731 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal, 0));
3732 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3733 new pm::AggregateAvg()));
3734 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3735 new pm::AggregateMin()));
3736 aCollector->registerMetric(new pm::Metric(fsUsage, fsUsageTotal,
3737 new pm::AggregateMax()));
3738 }
3739}
3740
3741void Host::i_registerMetrics(PerformanceCollector *aCollector)
3742{
3743 pm::CollectorHAL *hal = aCollector->getHAL();
3744 /* Create sub metrics */
3745 pm::SubMetric *cpuLoadUser = new pm::SubMetric("CPU/Load/User",
3746 "Percentage of processor time spent in user mode.");
3747 pm::SubMetric *cpuLoadKernel = new pm::SubMetric("CPU/Load/Kernel",
3748 "Percentage of processor time spent in kernel mode.");
3749 pm::SubMetric *cpuLoadIdle = new pm::SubMetric("CPU/Load/Idle",
3750 "Percentage of processor time spent idling.");
3751 pm::SubMetric *cpuMhzSM = new pm::SubMetric("CPU/MHz",
3752 "Average of current frequency of all processors.");
3753 pm::SubMetric *ramUsageTotal = new pm::SubMetric("RAM/Usage/Total",
3754 "Total physical memory installed.");
3755 pm::SubMetric *ramUsageUsed = new pm::SubMetric("RAM/Usage/Used",
3756 "Physical memory currently occupied.");
3757 pm::SubMetric *ramUsageFree = new pm::SubMetric("RAM/Usage/Free",
3758 "Physical memory currently available to applications.");
3759 pm::SubMetric *ramVMMUsed = new pm::SubMetric("RAM/VMM/Used",
3760 "Total physical memory used by the hypervisor.");
3761 pm::SubMetric *ramVMMFree = new pm::SubMetric("RAM/VMM/Free",
3762 "Total physical memory free inside the hypervisor.");
3763 pm::SubMetric *ramVMMBallooned = new pm::SubMetric("RAM/VMM/Ballooned",
3764 "Total physical memory ballooned by the hypervisor.");
3765 pm::SubMetric *ramVMMShared = new pm::SubMetric("RAM/VMM/Shared",
3766 "Total physical memory shared between VMs.");
3767
3768
3769 /* Create and register base metrics */
3770 pm::BaseMetric *cpuLoad = new pm::HostCpuLoadRaw(hal, this, cpuLoadUser, cpuLoadKernel,
3771 cpuLoadIdle);
3772 aCollector->registerBaseMetric(cpuLoad);
3773 pm::BaseMetric *cpuMhz = new pm::HostCpuMhz(hal, this, cpuMhzSM);
3774 aCollector->registerBaseMetric(cpuMhz);
3775 pm::BaseMetric *ramUsage = new pm::HostRamUsage(hal, this,
3776 ramUsageTotal,
3777 ramUsageUsed,
3778 ramUsageFree);
3779 aCollector->registerBaseMetric(ramUsage);
3780 pm::BaseMetric *ramVmm = new pm::HostRamVmm(aCollector->getGuestManager(), this,
3781 ramVMMUsed,
3782 ramVMMFree,
3783 ramVMMBallooned,
3784 ramVMMShared);
3785 aCollector->registerBaseMetric(ramVmm);
3786
3787 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser, 0));
3788 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3789 new pm::AggregateAvg()));
3790 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3791 new pm::AggregateMin()));
3792 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadUser,
3793 new pm::AggregateMax()));
3794
3795 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel, 0));
3796 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3797 new pm::AggregateAvg()));
3798 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3799 new pm::AggregateMin()));
3800 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadKernel,
3801 new pm::AggregateMax()));
3802
3803 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle, 0));
3804 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3805 new pm::AggregateAvg()));
3806 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3807 new pm::AggregateMin()));
3808 aCollector->registerMetric(new pm::Metric(cpuLoad, cpuLoadIdle,
3809 new pm::AggregateMax()));
3810
3811 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM, 0));
3812 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3813 new pm::AggregateAvg()));
3814 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3815 new pm::AggregateMin()));
3816 aCollector->registerMetric(new pm::Metric(cpuMhz, cpuMhzSM,
3817 new pm::AggregateMax()));
3818
3819 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal, 0));
3820 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3821 new pm::AggregateAvg()));
3822 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3823 new pm::AggregateMin()));
3824 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageTotal,
3825 new pm::AggregateMax()));
3826
3827 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed, 0));
3828 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3829 new pm::AggregateAvg()));
3830 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3831 new pm::AggregateMin()));
3832 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageUsed,
3833 new pm::AggregateMax()));
3834
3835 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree, 0));
3836 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3837 new pm::AggregateAvg()));
3838 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3839 new pm::AggregateMin()));
3840 aCollector->registerMetric(new pm::Metric(ramUsage, ramUsageFree,
3841 new pm::AggregateMax()));
3842
3843 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed, 0));
3844 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3845 new pm::AggregateAvg()));
3846 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3847 new pm::AggregateMin()));
3848 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMUsed,
3849 new pm::AggregateMax()));
3850
3851 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree, 0));
3852 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3853 new pm::AggregateAvg()));
3854 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3855 new pm::AggregateMin()));
3856 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMFree,
3857 new pm::AggregateMax()));
3858
3859 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned, 0));
3860 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3861 new pm::AggregateAvg()));
3862 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3863 new pm::AggregateMin()));
3864 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMBallooned,
3865 new pm::AggregateMax()));
3866
3867 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared, 0));
3868 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3869 new pm::AggregateAvg()));
3870 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3871 new pm::AggregateMin()));
3872 aCollector->registerMetric(new pm::Metric(ramVmm, ramVMMShared,
3873 new pm::AggregateMax()));
3874 i_registerDiskMetrics(aCollector);
3875}
3876
3877void Host::i_unregisterMetrics(PerformanceCollector *aCollector)
3878{
3879 aCollector->unregisterMetricsFor(this);
3880 aCollector->unregisterBaseMetricsFor(this);
3881}
3882
3883#endif /* VBOX_WITH_RESOURCE_USAGE_API */
3884
3885
3886/* static */
3887void Host::i_generateMACAddress(Utf8Str &mac)
3888{
3889 /*
3890 * Our strategy is as follows: the first three bytes are our fixed
3891 * vendor ID (080027). The remaining 3 bytes will be taken from the
3892 * start of a GUID. This is a fairly safe algorithm.
3893 */
3894 Guid guid;
3895 guid.create();
3896 mac = Utf8StrFmt("080027%02X%02X%02X",
3897 guid.raw()->au8[0], guid.raw()->au8[1], guid.raw()->au8[2]);
3898}
3899
3900#ifdef RT_OS_WINDOWS
3901HRESULT Host::i_getFixedDrivesFromGlobalNamespace(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &aDriveList) RT_NOEXCEPT
3902{
3903 RTERRINFOSTATIC ErrInfo;
3904 uint32_t offError;
3905 RTVFSDIR hVfsDir;
3906 int rc = RTVfsChainOpenDir("\\\\:iprtnt:\\GLOBAL??", 0 /*fFlags*/, &hVfsDir, &offError, RTErrInfoInitStatic(&ErrInfo));
3907 if (RT_FAILURE(rc))
3908 return setError(E_FAIL, tr("Failed to open NT\\GLOBAL?? (error %Rrc)"), rc);
3909
3910 /*
3911 * Scan whole directory and find any 'PhysicalDiskX' entries. Next, combine with '\\.\'
3912 * to obtain the harddisk dev path.
3913 */
3914 size_t cbDirEntryAlloced = sizeof(RTDIRENTRYEX);
3915 PRTDIRENTRYEX pDirEntry = (PRTDIRENTRYEX)RTMemTmpAlloc(cbDirEntryAlloced);
3916 if (!pDirEntry)
3917 {
3918 RTVfsDirRelease(hVfsDir);
3919 return setError(E_OUTOFMEMORY, tr("Out of memory! (direntry buffer)"));
3920 }
3921
3922 HRESULT hrc = S_OK;
3923 for (;;)
3924 {
3925 size_t cbDirEntry = cbDirEntryAlloced;
3926 rc = RTVfsDirReadEx(hVfsDir, pDirEntry, &cbDirEntry, RTFSOBJATTRADD_NOTHING);
3927 if (RT_FAILURE(rc))
3928 {
3929 if (rc == VERR_BUFFER_OVERFLOW)
3930 {
3931 RTMemTmpFree(pDirEntry);
3932 cbDirEntryAlloced = RT_ALIGN_Z(RT_MIN(cbDirEntry, cbDirEntryAlloced) + 64, 64);
3933 pDirEntry = (PRTDIRENTRYEX)RTMemTmpAlloc(cbDirEntryAlloced);
3934 if (pDirEntry)
3935 continue;
3936 hrc = setError(E_OUTOFMEMORY, tr("Out of memory! (direntry buffer)"));
3937 }
3938 else if (rc != VERR_NO_MORE_FILES)
3939 hrc = setError(VBOX_E_IPRT_ERROR, tr("RTVfsDirReadEx failed: %Rrc"), rc);
3940 break;
3941 }
3942 if (RTStrStartsWith(pDirEntry->szName, "PhysicalDrive"))
3943 {
3944 char szPhysicalDrive[64];
3945 RTStrPrintf(szPhysicalDrive, sizeof(szPhysicalDrive), "\\\\.\\%s", pDirEntry->szName);
3946
3947 RTFILE hRawFile = NIL_RTFILE;
3948 int vrc = RTFileOpen(&hRawFile, szPhysicalDrive, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
3949 if (RT_FAILURE(vrc))
3950 {
3951 try
3952 {
3953 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(szPhysicalDrive, tr("Unknown (Access denied)")));
3954 }
3955 catch (std::bad_alloc &)
3956 {
3957 hrc = setError(E_OUTOFMEMORY, tr("Out of memory"));
3958 break;
3959 }
3960 continue;
3961 }
3962
3963 DWORD cbBytesReturned = 0;
3964 uint8_t abBuffer[1024];
3965 RT_ZERO(abBuffer);
3966
3967 STORAGE_PROPERTY_QUERY query;
3968 RT_ZERO(query);
3969 query.PropertyId = StorageDeviceProperty;
3970 query.QueryType = PropertyStandardQuery;
3971
3972 BOOL fRc = DeviceIoControl((HANDLE)RTFileToNative(hRawFile),
3973 IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query),
3974 abBuffer, sizeof(abBuffer), &cbBytesReturned, NULL);
3975 RTFileClose(hRawFile);
3976 char szModel[1024];
3977 if (fRc)
3978 {
3979 PSTORAGE_DEVICE_DESCRIPTOR pDevDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)abBuffer;
3980 char *pszProduct = pDevDescriptor->ProductIdOffset ? (char *)&abBuffer[pDevDescriptor->ProductIdOffset] : NULL;
3981 if (pszProduct)
3982 {
3983 RTStrPurgeEncoding(pszProduct);
3984 if (*pszProduct != '\0')
3985 {
3986 char *pszVendor = pDevDescriptor->VendorIdOffset ? (char *)&abBuffer[pDevDescriptor->VendorIdOffset] : NULL;
3987 if (pszVendor)
3988 RTStrPurgeEncoding(pszVendor);
3989 if (pszVendor && *pszVendor)
3990 RTStrPrintf(szModel, sizeof(szModel), "%s %s", pszVendor, pszProduct);
3991 else
3992 RTStrCopy(szModel, sizeof(szModel), pszProduct);
3993 }
3994 }
3995 }
3996 try
3997 {
3998 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(szPhysicalDrive, szModel));
3999 }
4000 catch (std::bad_alloc &)
4001 {
4002 hrc = setError(E_OUTOFMEMORY, tr("Out of memory"));
4003 break;
4004 }
4005 }
4006 }
4007 if (FAILED(hrc))
4008 aDriveList.clear();
4009 RTMemTmpFree(pDirEntry);
4010 RTVfsDirRelease(hVfsDir);
4011 return hrc;
4012}
4013#endif
4014
4015/**
4016 * @throws nothing
4017 */
4018HRESULT Host::i_getDrivesPathsList(std::list<std::pair<com::Utf8Str, com::Utf8Str> > &aDriveList) RT_NOEXCEPT
4019{
4020#ifdef RT_OS_WINDOWS
4021 return i_getFixedDrivesFromGlobalNamespace(aDriveList);
4022
4023#elif defined(RT_OS_DARWIN)
4024 /*
4025 * Get the list of fixed drives from iokit.cpp and transfer it to aDriveList.
4026 */
4027 PDARWINFIXEDDRIVE pDrives = DarwinGetFixedDrives();
4028 HRESULT hrc;
4029 try
4030 {
4031 for (PDARWINFIXEDDRIVE pCurDrv = pDrives; pCurDrv; pCurDrv = pCurDrv->pNext)
4032 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(pCurDrv->szName, pCurDrv->pszModel));
4033 hrc = S_OK;
4034 }
4035 catch (std::bad_alloc &)
4036 {
4037 aDriveList.clear();
4038 hrc = E_OUTOFMEMORY;
4039 }
4040
4041 while (pDrives)
4042 {
4043 PDARWINFIXEDDRIVE pFreeMe = pDrives;
4044 pDrives = pDrives->pNext;
4045 ASMCompilerBarrier();
4046 RTMemFree(pFreeMe);
4047 }
4048 return hrc;
4049
4050#elif defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
4051 /*
4052 * The list of fixed drives is kept in the VBoxMainDriveInfo instance, so
4053 * update it and tranfer the info to aDriveList.
4054 *
4055 * This obviously requires us to write lock the object!
4056 */
4057 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4058 int vrc = m->hostDrives.updateFixedDrives(); /* nothrow */
4059 if (RT_FAILURE(vrc))
4060 return setErrorBoth(E_FAIL, vrc, tr("Failed to update fixed drive list (%Rrc)"), vrc);
4061
4062 try
4063 {
4064 for (DriveInfoList::const_iterator it = m->hostDrives.FixedDriveBegin(); it != m->hostDrives.FixedDriveEnd(); ++it)
4065 aDriveList.push_back(std::pair<com::Utf8Str, com::Utf8Str>(it->mDevice, it->mDescription));
4066 }
4067 catch (std::bad_alloc &)
4068 {
4069 aDriveList.clear();
4070 return E_OUTOFMEMORY;
4071 }
4072 return S_OK;
4073
4074#elif defined(RT_OS_SOLARIS)
4075 /*
4076 * We can get the info from HAL, if not present/working we'll get by
4077 * walking the device tree.
4078 */
4079# ifdef VBOX_USE_LIBHAL
4080 HRESULT hrc = i_getFixedDrivesFromHal(aDriveList);
4081 if (hrc != S_FALSE)
4082 return hrc;
4083 aDriveList.clear(); /* just in case */
4084# endif
4085 return i_getFixedDrivesFromDevTree(aDriveList);
4086
4087#else
4088 /* PORTME */
4089 RT_NOREF(aDriveList);
4090 return E_NOTIMPL;
4091#endif
4092}
4093
4094/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use