VirtualBox

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

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

Main/Host: Remove unnecessary include, noticed it from unexpected rebuilding.

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

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