VirtualBox

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

Last change on this file since 82968 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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

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