VirtualBox

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

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

Main/Update check: Settings fixes, added @todos. ​​bugref:7983

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

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