VirtualBox

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

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

Main/Update check: Big overhaul of the API and functionality.

  • Now uses VBOX_WITH_UPDATE_AGENT to entirely disable the feature (enabled by default).
  • Main: Uses new (more abstract) API as proposed in the latest UML docs.
  • Main: Added support for several events.
  • Main: Added support for update severities, order and dependencies (all optional).
  • Settings/XML: Now has own "Updates" branch to also cover other updatable components (later); not part of the system properties anymore.
  • Prepared for GuestAdditions and ExtPack updates.
  • FE/Qt: Adapted to new API.
  • FE/VBoxManage: Adapted to new API; uses more uniform (common) synopsis "modify" and "list" for modifying and listing (showing) update settings.
  • Docs: Fixed various typos, extended documentation.

Work in progress. bugref:7983

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