HostImpl.cpp revision 21455ffc7be41e8a015d9c515446100450b32195
/* $Id$ */
/** @file
* VirtualBox COM class implementation: Host
*/
/*
* Copyright (C) 2004-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
// for some reason Windows burns in sdk\...\winsock.h if this isn't included first
#include "HostImpl.h"
#ifdef VBOX_WITH_USB
# include "HostUSBDeviceImpl.h"
# include "USBDeviceFilterImpl.h"
# include "USBProxyService.h"
#endif // VBOX_WITH_USB
#include "HostNetworkInterfaceImpl.h"
#include "HostVideoInputDeviceImpl.h"
#include "MachineImpl.h"
#include "AutoCaller.h"
#include "Logging.h"
#include "Performance.h"
#include "MediumImpl.h"
#include "HostPower.h"
#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
# include <HostHardwareLinux.h>
#endif
# include <set>
#endif
#ifdef VBOX_WITH_RESOURCE_USAGE_API
# include "PerformanceImpl.h"
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
# include <VBox/VBoxNetCfg-win.h>
#endif /* #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
#endif
#ifdef RT_OS_LINUX
# include <errno.h>
#endif /* RT_OS_LINUX */
#ifdef RT_OS_SOLARIS
# include <fcntl.h>
# include <unistd.h>
# include <stropts.h>
# include <errno.h>
# include <limits.h>
# include <stdio.h>
# include <libdevinfo.h>
/* Dynamic loading of libhal on Solaris hosts */
# ifdef VBOX_USE_LIBHAL
# include "vbox-libhal.h"
extern "C" char *getfullrawname(char *);
# endif
# include "solaris/DynLoadLibSolaris.h"
/**
* Solaris DVD drive list as returned by getDVDInfoFromDevTree().
*/
typedef struct SOLARISDVD
{
struct SOLARISDVD *pNext;
char szDescription[512];
char szRawDiskPath[PATH_MAX];
} SOLARISDVD;
/** Pointer to a Solaris DVD descriptor. */
typedef SOLARISDVD *PSOLARISDVD;
#endif /* RT_OS_SOLARIS */
#ifdef RT_OS_WINDOWS
# define _WIN32_DCOM
# include <windows.h>
# include <shellapi.h>
# define INITGUID
# include <guiddef.h>
# include <devguid.h>
# include <objbase.h>
//# include <setupapi.h>
# include <shlobj.h>
# include <cfgmgr32.h>
#endif /* RT_OS_WINDOWS */
#ifdef RT_OS_DARWIN
#endif
#ifdef VBOX_WITH_CROGL
#include <VBox/VBoxOGLTest.h>
#endif /* VBOX_WITH_CROGL */
#include <iprt/asm-amd64-x86.h>
#ifndef RT_OS_WINDOWS
#endif
#ifdef RT_OS_SOLARIS
#endif
#ifdef VBOX_WITH_HOSTNETIF_API
# include "netif.h"
#endif
#include <VBox/settings.h>
#include "VBox/com/MultiResult.h"
#include <stdio.h>
#include <algorithm>
#include <string>
#include <vector>
#include "HostDnsService.h"
////////////////////////////////////////////////////////////////////////////////
//
// Host private data definition
//
////////////////////////////////////////////////////////////////////////////////
{
Data()
:
fDVDDrivesListBuilt(false),
fFloppyDrivesListBuilt(false)
{};
#ifdef VBOX_WITH_USB
/** Pointer to the USBProxyService object. */
#endif /* VBOX_WITH_USB */
// list of host drives; lazily created by getDVDDrives() and getFloppyDrives(),
// and protected by the medium tree lock handle (including the bools).
bool fDVDDrivesListBuilt,
#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
/** Object with information about host drives */
#endif
/** @name Features that can be queried with GetProcessorFeature.
* @{ */
bool fVTSupported,
/** @} */
/** 3D hardware acceleration supported? Tristate, -1 meaning not probed. */
/** Host's DNS informaton fetching */
};
////////////////////////////////////////////////////////////////////////////////
//
// Constructor / destructor
//
////////////////////////////////////////////////////////////////////////////////
{
return BaseFinalConstruct();
}
void Host::FinalRelease()
{
uninit();
}
/**
* Initializes the host object.
*
* @param aParent VirtualBox parent object.
*/
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
m = new Data();
#ifdef VBOX_WITH_USB
/*
* Create and initialize the USB Proxy Service.
*/
# if defined (RT_OS_DARWIN)
m->pUSBProxyService = new USBProxyServiceDarwin(this);
# elif defined (RT_OS_LINUX)
m->pUSBProxyService = new USBProxyServiceLinux(this);
m->pUSBProxyService = new USBProxyServiceOs2(this);
# elif defined (RT_OS_SOLARIS)
m->pUSBProxyService = new USBProxyServiceSolaris(this);
# elif defined (RT_OS_WINDOWS)
m->pUSBProxyService = new USBProxyServiceWindows(this);
# elif defined (RT_OS_FREEBSD)
m->pUSBProxyService = new USBProxyServiceFreeBSD(this);
# else
m->pUSBProxyService = new USBProxyService(this);
# endif
#endif /* VBOX_WITH_USB */
#ifdef VBOX_WITH_RESOURCE_USAGE_API
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
/* Create the list of network interfaces so their metrics get registered. */
#if defined (RT_OS_WINDOWS)
#elif defined (RT_OS_DARWIN)
#else
#endif
/* Cache the features reported by GetProcessorFeature. */
m->fVTSupported = false;
m->fLongModeSupported = false;
m->fPAESupported = false;
m->fNestedPagingSupported = false;
m->fRecheckVTSupported = false;
if (ASMHasCpuId())
{
/* Note! This code is duplicated in SUPDrv.c and other places! */
if (ASMIsValidStdRange(uMaxId))
{
/* PAE? */
/* Long Mode? */
#if defined(RT_OS_DARWIN) && ARCH_BITS == 32 /* darwin.x86 has some optimizations of 64-bit on 32-bit. */
int f64bitCapable = 0;
m->fLongModeSupported = f64bitCapable != 0;
#endif
/* VT-x? */
{
if ( (fFeaturesEcx & X86_CPUID_FEATURE_ECX_VMX)
)
{
int rc = SUPR3QueryVTxSupported();
if (RT_SUCCESS(rc))
m->fVTSupported = true;
}
}
/* AMD-V */
{
)
{
m->fVTSupported = true;
/* Query AMD features. */
if (uExtMaxId >= 0x8000000a)
{
m->fNestedPagingSupported = true;
}
}
}
}
}
/* Check with SUPDrv if VT-x and AMD-V are really supported (may fail). */
if (m->fVTSupported)
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (fVTCaps & SUPVTCAPS_NESTED_PAGING)
m->fNestedPagingSupported = true;
else
Assert(m->fNestedPagingSupported == false);
}
else
{
m->fVTSupported = m->fNestedPagingSupported = false;
}
}
else
m->fRecheckVTSupported = true; /* Try again later when the driver is loaded. */
}
#ifdef VBOX_WITH_CROGL
/* Test for 3D hardware acceleration support later when (if ever) need. */
m->f3DAccelerationSupported = -1;
#else
m->f3DAccelerationSupported = false;
#endif
/* Extract the list of configured host-only interfaces */
{
continue;
pos - sizeof("HostOnly")));
}
++it)
{
int r = NetIfCreateHostOnlyNetworkInterface(m->pParent,
hif.asOutParam(),
if (RT_FAILURE(r))
}
#endif /* defined (RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) */
/* Confirm a successful initialization */
return S_OK;
}
/**
* Uninitializes the host object and sets the ready flag to FALSE.
* Called either from FinalRelease() or by the parent when it gets destroyed.
*/
{
LogFlowThisFunc(("\n"));
/* Enclose the state transition Ready->InUninit->NotReady */
AutoUninitSpan autoUninitSpan(this);
if (autoUninitSpan.uninitDone())
return;
#ifdef VBOX_WITH_RESOURCE_USAGE_API
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
/*
* Note that unregisterMetrics() has unregistered all metrics associated
* with Host including network interface ones. We can destroy network
* interface objects now.
*/
#ifdef VBOX_WITH_USB
/* wait for USB proxy service to terminate before we uninit all USB
* devices */
LogFlowThisFunc(("Stopping USB proxy service...\n"));
delete m->pUSBProxyService;
m->pUSBProxyService = NULL;
LogFlowThisFunc(("Done stopping USB proxy service.\n"));
#endif
delete m->pHostPowerService;
#ifdef VBOX_WITH_USB
/* uninit all USB device filters still referenced by clients
* Note! HostUSBDeviceFilter::uninit() will modify llChildren. */
while (!m->llChildren.empty())
{
}
m->llUSBDeviceFilters.clear();
#endif
delete m;
m = NULL;
}
////////////////////////////////////////////////////////////////////////////////
//
// ISnapshot public methods
//
////////////////////////////////////////////////////////////////////////////////
/**
* Returns a list of host DVD drives.
*
* @returns COM status code
* @param drives address of result pointer
*/
{
{
size_t i = 0;
{
}
}
return rc;
}
/**
* Returns a list of host floppy drives.
*
* @returns COM status code
* @param drives address of result pointer
*/
{
{
size_t i = 0;
{
}
}
return rc;
}
#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
# define VBOX_APP_NAME L"VirtualBox"
{
int rc = VERR_GENERAL_FAILURE;
{
{
/* create a new object and add it to the list */
/* remove the curly bracket at the end */
{
// iface->setVirtualBox(m->pParent);
rc = VINF_SUCCESS;
}
else
{
Assert(0);
}
}
}
return rc;
}
#endif /* defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT) */
/**
* Returns a list of host network interfaces.
*
* @returns COM status code
* @param drives address of result pointer
*/
{
# ifdef VBOX_WITH_HOSTNETIF_API
int rc = i_updateNetIfList();
if (rc)
{
}
size_t i = 0;
for (HostNetworkInterfaceList::iterator it = m->llNetIfs.begin(); it != m->llNetIfs.end(); ++it, ++i)
{
}
return S_OK;
# else
# if defined(RT_OS_DARWIN)
while (pEtherNICs)
{
if (SUCCEEDED(IfObj->init(Bstr(pEtherNICs->szName), Guid(pEtherNICs->Uuid), HostNetworkInterfaceType_Bridged)))
/* next, free current */
void *pvFree = pEtherNICs;
}
# elif defined RT_OS_WINDOWS
# ifndef VBOX_WITH_NETFLT
# else /* # if defined VBOX_WITH_NETFLT */
/* we are using the INetCfg API for getting the list of miniports */
&pNc,
&lpszApp);
{
# ifdef VBOX_NETFLT_ONDEMAND_BIND
/* for the protocol-based approach for now we just get all miniports the MS_TCPIP protocol binds to */
# else
/* for the filter-based approach we get all miniports our filter (sun_VBoxNetFlt)is bound to */
# ifndef VBOX_WITH_HARDENING
{
/* TODO: try to install the netflt from here */
}
# endif
# endif
{
{
{
/* S_OK == enabled, S_FALSE == disabled */
{
{
{
{
{
if (uComponentStatus == 0)
{
}
}
}
}
}
}
}
}
}
else
{
}
}
# endif /* # if defined VBOX_WITH_NETFLT */
# elif defined RT_OS_LINUX
if (sock >= 0)
{
char pBuffer[2048];
{
{
{
{
}
}
}
}
}
# endif /* RT_OS_LINUX */
return S_OK;
# endif
#else
/* Not implemented / supported on this platform. */
#endif
}
{
#ifdef VBOX_WITH_USB
aUSBDevices.resize(0);
{
}
return rc;
#else
/* Note: The GUI depends on this method returning E_NOTIMPL with no
* extended error info to indicate that USB is simply not available
* (w/o treating it as a failure), for example, as in OSE. */
# ifndef RT_OS_WINDOWS
# endif
#endif
return S_OK;
}
/**
* This method return the list of registered name servers
*/
{
aNameServers.resize(0);
{
}
return rc;
}
/**
* This method returns the domain name of the host
*/
{
return rc;
/* XXX: note here should be synchronization with thread polling state
* changes in name resoving system on host */
}
/**
* This method returns the search string.
*/
{
{
}
return rc;
}
{
#ifdef VBOX_WITH_USB
size_t i = 0;
for (USBDeviceFilterList::iterator it = m->llUSBDeviceFilters.begin(); it != m->llUSBDeviceFilters.end(); ++it, ++i)
{
}
return rc;
#else
/* Note: The GUI depends on this method returning E_NOTIMPL with no
* extended error info to indicate that USB is simply not available
* (w/o treating it as a failure), for example, as in OSE. */
# ifndef RT_OS_WINDOWS
# endif
#endif
}
/**
* Returns the number of installed logical processors
*
* @returns VBOX status code
* @param count address of result variable
*/
{
// no locking required
*aCount = RTMpGetPresentCount();
return S_OK;
}
/**
* Returns the number of online logical processors
*
* @returns COM status code
* @param count address of result variable
*/
{
// no locking required
*aCount = RTMpGetOnlineCount();
return S_OK;
}
/**
* Returns the number of installed physical processor cores.
*
* @returns COM status code
* @param count address of result variable
*/
{
// no locking required
return S_OK;
}
/**
* Returns the number of installed physical processor cores.
*
* @returns COM status code
* @param count address of result variable
*/
{
// no locking required
*aCount = RTMpGetOnlineCoreCount();
return S_OK;
}
/**
* Returns the (approximate) maximum speed of the given host CPU in MHz
*
* @returns COM status code
* @param cpu id to get info for.
* @param speed address of result variable, speed is 0 if unknown or aCpuId is invalid.
*/
{
// no locking required
return S_OK;
}
/**
* Returns a description string for the host CPU
*
* @returns COM status code
* @param cpu id to get info for.
* @param description address of result variable, empty string if not known or aCpuId is invalid.
*/
{
// no locking required
char szCPUModel[80];
szCPUModel[0] = *"\0";
if (RT_FAILURE(vrc))
return E_FAIL; /** @todo error reporting? */
return S_OK;
}
/**
* Returns whether a host processor feature is supported or not
*
* @returns COM status code
* @param Feature to query.
* @param address of supported bool result variable
*/
{
/* Validate input. */
switch (aFeature)
{
case ProcessorFeature_PAE:
break;
default:
return setError(E_INVALIDARG, tr("The aFeature value %d (%#x) is out of range."), (int)aFeature, (int)aFeature);
}
/* Do the job. */
AutoCaller autoCaller(this);
{
if ( m->fRecheckVTSupported
&& ( aFeature == ProcessorFeature_HWVirtEx
)
{
/* Perhaps the driver is available now... */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (fVTCaps & SUPVTCAPS_NESTED_PAGING)
m->fNestedPagingSupported = true;
else
Assert(m->fNestedPagingSupported == false);
}
else
{
m->fVTSupported = m->fNestedPagingSupported = true;
}
}
}
switch (aFeature)
{
*aSupported = m->fVTSupported;
break;
case ProcessorFeature_PAE:
*aSupported = m->fPAESupported;
break;
*aSupported = m->fLongModeSupported;
break;
*aSupported = m->fNestedPagingSupported;
break;
default:
AssertFailed();
}
}
return hrc;
}
/**
* Returns the specific CPUID leaf.
*
* @returns COM status code
* @param aCpuId The CPU number. Mostly ignored.
* @param aLeaf The leaf number.
* @param aSubLeaf The sub-leaf number.
* @param aValEAX Where to return EAX.
* @param aValEBX Where to return EBX.
* @param aValECX Where to return ECX.
* @param aValEDX Where to return EDX.
*/
{
// no locking required
/* Check that the CPU is online. */
/** @todo later use RTMpOnSpecific. */
if (!RTMpIsCpuOnline(aCpuId))
return RTMpIsCpuPresent(aCpuId)
return S_OK;
}
/**
* Returns the amount of installed system memory in megabytes
*
* @returns COM status code
* @param size address of result variable
*/
{
// no locking required
if (RT_FAILURE(rc))
return E_FAIL;
return S_OK;
}
/**
* Returns the current system memory free space in megabytes
*
* @returns COM status code
* @param available address of result variable
*/
{
// no locking required
if (RT_FAILURE(rc))
return E_FAIL;
return S_OK;
}
/**
* Returns the name string of the host operating system
*
* @returns COM status code
* @param os address of result variable
*/
{
// no locking required
char szOSName[80];
if (RT_FAILURE(vrc))
return E_FAIL; /** @todo error reporting? */
return S_OK;
}
/**
* Returns the version string of the host operating system
*
* @returns COM status code
* @param os address of result variable
*/
{
// no locking required
/* Get the OS release. Reserve some buffer space for the service pack. */
char szOSRelease[128];
if (RT_FAILURE(vrc))
return E_FAIL; /** @todo error reporting? */
/* Append the service pack if present. */
char szOSServicePack[80];
if (RT_FAILURE(vrc))
{
if (vrc != VERR_NOT_SUPPORTED)
return E_FAIL; /** @todo error reporting? */
szOSServicePack[0] = '\0';
}
if (szOSServicePack[0] != '\0')
{
}
return S_OK;
}
/**
* Returns the current host time in milliseconds since 1970-01-01 UTC.
*
* @returns COM status code
* @param time address of result variable
*/
{
// no locking required
return S_OK;
}
{
if (m->f3DAccelerationSupported != -1)
else
{
#ifdef VBOX_WITH_CROGL
bool fSupported = VBoxOglIs3DAccelerationSupported();
#else
bool fSupported = false; /* shoudn't get here, but just in case. */
#endif
*aSupported = fSupported;
}
#ifdef DEBUG_misha
AssertMsgFailed(("should not be here any more!\n"));
#endif
return hrc;
}
{
#ifdef VBOX_WITH_HOSTNETIF_API
/* No need to lock anything. If there ever will - watch out, the function
* called below grabs the VirtualBox lock. */
if (RT_SUCCESS(r))
{
if (!iHn)
tr("Unable to create a host network interface"));
#if !defined(RT_OS_WINDOWS)
/*
* We need to write the default IP address and mask to extra data now,
* so the interface gets re-created after vboxnetadp.ko reload.
* Note that we avoid calling EnableStaticIpConfig since it would
* change the address on host's interface as well and we want to
* postpone the change until VM actually starts.
*/
#endif
}
return S_OK;
#else
return E_NOTIMPL;
#endif
}
{
#ifdef VBOX_WITH_HOSTNETIF_API
/* No need to lock anything, the code below does not touch the state
* of the host object. If that ever changes then check for lock order
* violations with the called functions. */
/* first check whether an interface with the given name already exists */
{
return setError(VBOX_E_OBJECT_NOT_FOUND,
tr("Host network interface with UUID {%RTuuid} does not exist"),
}
if (RT_SUCCESS(r))
{
/* Drop configuration parameters for removed interface */
return S_OK;
}
#else
return E_NOTIMPL;
#endif
}
{
#ifdef VBOX_WITH_USB
return S_OK;
#else
/* Note: The GUI depends on this method returning E_NOTIMPL with no
* extended error info to indicate that USB is simply not available
* (w/o treating it as a failure), for example, as in OSE. */
#endif
}
{
#ifdef VBOX_WITH_USB
/* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
clearError();
++it)
{
{
break;
}
}
return setError(VBOX_E_INVALID_OBJECT_STATE,
tr("The given USB device filter is not created within this VirtualBox instance"));
return setError(E_INVALIDARG,
tr("The given USB device filter is already in the list"));
/* iterate to the position... */
/* ...and insert */
/* notify the proxy (only when the filter is active) */
if ( m->pUSBProxyService->isActive()
{
}
// save the global settings; for that we should hold only the VirtualBox lock
#else
/* Note: The GUI depends on this method returning E_NOTIMPL with no
* extended error info to indicate that USB is simply not available
* (w/o treating it as a failure), for example, as in OSE. */
#endif
}
{
#ifdef VBOX_WITH_USB
/* Note: HostUSBDeviceFilter and USBProxyService also uses this lock. */
clearError();
if (!m->llUSBDeviceFilters.size())
return setError(E_INVALIDARG,
tr("The USB device filter list is empty"));
return setError(E_INVALIDARG,
tr("Invalid position: %lu (must be in range [0, %lu])"),
{
/* iterate to the position... */
/* ...get an element from there... */
/* ...and remove */
}
/* notify the proxy (only when the filter is active) */
{
}
// save the global settings; for that we should hold only the VirtualBox lock
#else
/* Note: The GUI depends on this method returning E_NOTIMPL with no
* extended error info to indicate that USB is simply not available
* (w/o treating it as a failure), for example, as in OSE. */
#endif
}
{
else
rc = setError(rc, Medium::tr("The host DVD drive named '%ls' could not be found"), Bstr(aName).raw());
return rc;
}
{
else
return setError(rc, Medium::tr("The host floppy drive named '%ls' could not be found"), Bstr(aName).raw());
}
{
#ifndef VBOX_WITH_HOSTNETIF_API
return E_NOTIMPL;
#else
return E_INVALIDARG;
if (!aNetworkInterface)
return E_POINTER;
int rc = i_updateNetIfList();
if (RT_FAILURE(rc))
{
return E_FAIL;
}
{
Bstr n;
if (n == aName)
}
if (!found)
return setError(E_INVALIDARG,
#endif
}
{
#ifndef VBOX_WITH_HOSTNETIF_API
return E_NOTIMPL;
#else
return E_INVALIDARG;
if (!aNetworkInterface)
return E_POINTER;
int rc = i_updateNetIfList();
if (RT_FAILURE(rc))
{
return E_FAIL;
}
{
Bstr g;
}
if (!found)
return setError(E_INVALIDARG,
#endif
}
{
#ifdef VBOX_WITH_HOSTNETIF_API
int rc = i_updateNetIfList();
if (RT_FAILURE(rc))
return E_FAIL;
{
return hr;
if (t == aType)
}
size_t i = 0;
{
}
return S_OK;
#else
return E_NOTIMPL;
#endif
}
{
#ifdef VBOX_WITH_USB
{
{
return S_OK;
}
}
return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
tr("Could not find a USB device with address '%ls'"),
#else /* !VBOX_WITH_USB */
return E_NOTIMPL;
#endif /* !VBOX_WITH_USB */
}
{
#ifdef VBOX_WITH_USB
return E_INVALIDARG;
{
{
return rc;
}
}
"Could not find a USB device with uuid {%RTuuid}"),
#else /* !VBOX_WITH_USB */
return E_NOTIMPL;
#endif /* !VBOX_WITH_USB */
}
{
// no locking required
return S_OK;
}
/**
* Returns a list of host video capture devices (webcams, etc).
*
* @returns COM status code
* @param aVideoInputDevices Array of interface pointers to be filled.
*/
{
{
size_t i = 0;
{
}
}
return hr;
}
// public methods only for internal purposes
////////////////////////////////////////////////////////////////////////////////
{
#ifdef VBOX_WITH_USB
AutoCaller autoCaller(this);
++it)
{
/* notify the proxy (only when the filter is active) */
{
}
}
#else
#endif /* VBOX_WITH_USB */
return rc;
}
{
#ifdef VBOX_WITH_USB
AutoCaller autoCaller(this);
++it)
{
pFilter->saveSettings(f);
}
#else
#endif /* VBOX_WITH_USB */
return S_OK;
}
/**
* Sets the given pointer to point to the static list of DVD or floppy
* drives in the Host instance data, depending on the @a mediumType
* parameter.
*
* This builds the list on the first call; it adds or removes host drives
* that may have changed if fRefresh == true.
*
* The caller must hold the medium tree write lock before calling this.
* To protect the list to which the caller's pointer points, the caller
* must also hold that lock.
*
* @param mediumType Must be DeviceType_Floppy or DeviceType_DVD.
* @param fRefresh Whether to refresh the host drives list even if this is not the first call.
* @param pll Caller's pointer which gets set to the static list of host drives.
* @return
*/
bool fRefresh,
{
bool *pfListBuilt = NULL;
switch (mediumType)
{
case DeviceType_DVD:
if (!m->fDVDDrivesListBuilt || fRefresh)
{
return rc;
pfListBuilt = &m->fDVDDrivesListBuilt;
}
pllCached = &m->llDVDDrives;
break;
case DeviceType_Floppy:
if (!m->fFloppyDrivesListBuilt || fRefresh)
{
return rc;
}
pllCached = &m->llFloppyDrives;
break;
default:
return E_INVALIDARG;
}
if (pfListBuilt)
{
// a list was built in llNew above:
if (!*pfListBuilt)
{
// this was the first call (instance bool is still false): then just copy the whole list and return
// and mark the instance data as "built"
*pfListBuilt = true;
}
else
{
// list was built, and this was a subsequent call: then compare the old and the new lists
// remove drives from the cached list which are no longer present
/*nothing */)
{
bool fFound = false;
++itNew)
{
if (strLocationNew == strLocationCached)
{
fFound = true;
break;
}
}
if (!fFound)
else
++itCached;
}
// add drives to the cached list that are not on there yet
++itNew)
{
bool fFound = false;
++itCached)
{
if (strLocationNew == strLocationCached)
{
fFound = true;
break;
}
}
if (!fFound)
}
}
}
// return cached list to caller
return rc;
}
/**
* Goes through the list of host drives that would be returned by getDrives()
* and looks for a host drive with the given UUID. If found, it sets pMedium
* to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
*
* @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
* @param uuid Medium UUID of host drive to look for.
* @param fRefresh Whether to refresh the host drives list (see getDrives())
* @param pMedium Medium object, if found…
* @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
*/
bool fRefresh,
{
{
++it)
{
{
return S_OK;
}
}
}
return VBOX_E_OBJECT_NOT_FOUND;
}
/**
* Goes through the list of host drives that would be returned by getDrives()
* and looks for a host drive with the given name. If found, it sets pMedium
* to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
*
* @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
* @param strLocationFull Name (path) of host drive to look for.
* @param fRefresh Whether to refresh the host drives list (see getDrives())
* @param pMedium Medium object, if found…
* @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
*/
const Utf8Str &strLocationFull,
bool fRefresh,
{
{
++it)
{
{
return S_OK;
}
}
}
return VBOX_E_OBJECT_NOT_FOUND;
}
/**
* Goes through the list of host drives that would be returned by getDrives()
* and looks for a host drive with the given name, location or ID. If found,
* it sets pMedium to that drive; otherwise returns VBOX_E_OBJECT_NOT_FOUND.
*
* @param mediumType Must be DeviceType_DVD or DeviceType_Floppy.
* @param strNameOrId Name or full location or UUID of host drive to look for.
* @param pMedium Medium object, if found…
* @return VBOX_E_OBJECT_NOT_FOUND if not found, or S_OK if found, or errors from getDrives().
*/
const Utf8Str &strNameOrId,
{
// string is not a syntactically valid UUID: try a name then
}
/**
* Called from getDrives() to build the DVD drives list.
* @param pll
* @return
*/
{
try
{
#if defined(RT_OS_WINDOWS)
TCHAR *p = hostDrives;
do
{
if (GetDriveType(p) == DRIVE_CDROM)
{
driveName[0] = *p;
}
p += _tcslen(p) + 1;
}
while (*p);
delete[] hostDrives;
#elif defined(RT_OS_SOLARIS)
# ifdef VBOX_USE_LIBHAL
if (!i_getDVDInfoFromHal(list))
# endif
{
}
{
}
#elif defined(RT_OS_DARWIN)
while (cur)
{
/* next */
}
#else
/* PORTME */
#endif
}
{
rc = E_OUTOFMEMORY;
}
return rc;
}
/**
* Called from getDrives() to build the floppy drives list.
* @param list
* @return
*/
{
try
{
#ifdef RT_OS_WINDOWS
TCHAR *p = hostDrives;
do
{
if (GetDriveType(p) == DRIVE_REMOVABLE)
{
driveName[0] = *p;
}
p += _tcslen(p) + 1;
}
while (*p);
delete[] hostDrives;
#elif defined(RT_OS_LINUX)
{
}
#else
/* PORTME */
#endif
}
{
rc = E_OUTOFMEMORY;
}
return rc;
}
#ifdef VBOX_WITH_USB
{
return m->pUSBProxyService;
}
{
AutoCaller autoCaller(this);
return S_OK;
}
{
AutoCaller autoCaller(this);
++it)
{
{
break;
}
}
return S_OK;
}
{
return m->pParent;
}
/**
* Called by setter methods of all USB device filters.
*/
{
AutoCaller autoCaller(this);
{
if (aActiveChanged)
{
{
}
else
{
}
}
else
{
{
// update the filter in the proxy
}
}
// save the global settings... yeah, on every single filter property change
// for that we should hold only the VirtualBox lock
return m->pParent->saveSettings();
}
return S_OK;
}
/**
* Interface for obtaining a copy of the USBDeviceFilterList,
* used by the USBProxyService.
*
* @param aGlobalFilters Where to put the global filter list copy.
* @param aMachines Where to put the machine vector.
*/
{
*aGlobalFilters = m->llUSBDeviceFilters;
}
#endif /* VBOX_WITH_USB */
// private methods
////////////////////////////////////////////////////////////////////////////////
#if defined(RT_OS_SOLARIS) && defined(VBOX_USE_LIBHAL)
/**
* Helper function to get the slice number from a device path
*
* @param pszDevLinkPath Pointer to a device path (/dev/(r)dsk/c7d1t0d0s3 etc.)
* @returns Pointer to the slice portion of the given path.
*/
static char *solarisGetSliceFromPath(const char *pszDevLinkPath)
{
else
return pszFound;
return NULL;
}
/**
* Walk device links and returns an allocated path for the first one in the snapshot.
*
* @param DevLink Handle to the device link being walked.
* @param pvArg Opaque data containing the pointer to the path.
* @returns Pointer to an allocated device path string.
*/
{
return DI_WALK_TERMINATE;
}
/**
* @param Node Handle to the current node.
* @param pvArg Opaque data (holds list pointer).
* @returns Solaris specific code whether to continue walking or not.
*/
{
/*
* Check for "removable-media" or "hotpluggable" instead of "SCSI" so that we also include USB CD-ROMs.
* As unfortunately the Solaris drivers only export these common properties.
*/
{
{
char *pszProduct = NULL;
{
{
/*
* Found a DVD drive, we need to scan the minor nodes to find the correct
*/
if (DevLink)
{
{
{
continue;
}
if (!pszMinorPath)
continue;
char *pszDevLinkPath = NULL;
if (pszDevLinkPath)
{
{
/*
* We've got a fully qualified DVD drive. Add it to the list.
*/
{
if (*ppDrives)
/* We're not interested in any of the other slices, stop minor nodes traversal. */
break;
}
}
}
}
}
}
}
}
}
return DI_WALK_CONTINUE;
}
/**
* Works on Solaris 10 as well as OpenSolaris without depending on libhal.
*/
{
if (RootNode != DI_NODE_NIL)
while (pDrives)
{
hostDVDDriveObj->init(m->pParent, DeviceType_DVD, Bstr(pDrives->szRawDiskPath), Bstr(pDrives->szDescription));
}
}
/* Solaris hosts, loading libhal at runtime */
/**
* Helper function to query the hal subsystem for information about DVD drives attached to the
* system.
*
* @returns true if information was successfully obtained, false otherwise
* @retval list drives found will be attached to this list
*/
{
bool halSuccess = false;
if (!gLibHalCheckPresence())
return false;
if (dbusConnection != 0)
{
if (halContext != 0)
{
{
{
int numDevices;
"storage.drive_type", "cdrom",
&numDevices, &dbusError);
if (halDevices != 0)
{
/* Hal is installed and working, so if no devices are reported, assume
that there are none. */
halSuccess = true;
for (int i = 0; i < numDevices; i++)
{
#ifdef RT_OS_SOLARIS
#endif
if (devNode != 0)
{
// if (validateDevice(devNode, true))
// {
/* We do not check the error here, as this field may
not even exist. */
halDevices[i], "info.vendor", 0);
{
{
}
else
{
}
}
else
{
if (product == 0)
{
LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
}
}
if (vendor != 0)
{
}
if (product != 0)
{
}
// }
// else
// {
// LogRel(("Host::COMGETTER(DVDDrives): failed to validate the block device %s as a DVD drive\n"));
// }
#ifndef RT_OS_SOLARIS
#else
#endif
}
else
{
LogRel(("Host::COMGETTER(DVDDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
}
}
}
else
{
LogRel(("Host::COMGETTER(DVDDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
}
{
LogRel(("Host::COMGETTER(DVDDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
}
}
else
{
LogRel(("Host::COMGETTER(DVDDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
}
}
else
{
LogRel(("Host::COMGETTER(DVDDrives): failed to set libhal connection to dbus.\n"));
}
}
else
{
LogRel(("Host::COMGETTER(DVDDrives): failed to get a libhal context - out of memory?\n"));
}
}
else
{
LogRel(("Host::COMGETTER(DVDDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
}
return halSuccess;
}
/**
* Helper function to query the hal subsystem for information about floppy drives attached to the
* system.
*
* @returns true if information was successfully obtained, false otherwise
* @retval list drives found will be attached to this list
*/
{
bool halSuccess = false;
if (!gLibHalCheckPresence())
return false;
if (dbusConnection != 0)
{
if (halContext != 0)
{
{
{
int numDevices;
"storage.drive_type", "floppy",
&numDevices, &dbusError);
if (halDevices != 0)
{
/* Hal is installed and working, so if no devices are reported, assume
that there are none. */
halSuccess = true;
for (int i = 0; i < numDevices; i++)
{
halDevices[i], "storage.drive_type", 0);
if (driveType != 0)
{
{
continue;
}
}
else
{
/* An error occurred. The attribute "storage.drive_type"
probably didn't exist. */
continue;
}
if (devNode != 0)
{
// if (validateDevice(devNode, false))
// {
/* We do not check the error here, as this field may
not even exist. */
halDevices[i], "info.vendor", 0);
{
{
}
else
{
}
}
else
{
if (product == 0)
{
LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"info.product\" for device %s. dbus error: %s (%s)\n",
}
}
if (vendor != 0)
{
}
if (product != 0)
{
}
// }
// else
// {
// LogRel(("Host::COMGETTER(FloppyDrives): failed to validate the block device %s as a floppy drive\n"));
// }
}
else
{
LogRel(("Host::COMGETTER(FloppyDrives): failed to get property \"block.device\" for device %s. dbus error: %s (%s)\n",
}
}
}
else
{
LogRel(("Host::COMGETTER(FloppyDrives): failed to get devices with capability \"storage.cdrom\". dbus error: %s (%s)\n", dbusError.name, dbusError.message));
}
{
LogRel(("Host::COMGETTER(FloppyDrives): failed to shutdown the libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
}
}
else
{
LogRel(("Host::COMGETTER(FloppyDrives): failed to initialise libhal context. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
}
}
else
{
LogRel(("Host::COMGETTER(FloppyDrives): failed to set libhal connection to dbus.\n"));
}
}
else
{
LogRel(("Host::COMGETTER(FloppyDrives): failed to get a libhal context - out of memory?\n"));
}
}
else
{
LogRel(("Host::COMGETTER(FloppyDrives): failed to connect to dbus. dbus error: %s (%s)\n", dbusError.name, dbusError.message));
}
return halSuccess;
}
#endif /* RT_OS_SOLARIS and VBOX_USE_HAL */
/** @todo get rid of dead code below - RT_OS_SOLARIS and RT_OS_LINUX are never both set */
#if defined(RT_OS_SOLARIS)
/**
* Helper function to parse the given mount file and add found entries
*/
{
#ifdef RT_OS_LINUX
if (mtab)
{
char *mnt_type;
char *mnt_dev;
char *tmp;
{
// supermount fs case
{
if (tmp)
{
if (mnt_type)
{
if (tmp)
*tmp = '\0';
}
}
if (tmp)
{
if (mnt_dev)
{
if (tmp)
*tmp = '\0';
}
}
}
// use strstr here to cover things fs types like "udf,iso9660"
{
/** @todo check whether we've already got the drive in our list! */
if (validateDevice(mnt_dev, true))
{
}
}
}
}
#else // RT_OS_SOLARIS
if (mntFile)
{
{
{
// skip devices we are not interested in
{
if (validateDevice(rawDevName, true))
{
}
}
}
}
}
#endif
}
/**
* Helper function to check whether the given device node is a valid drive
*/
{
bool retValue = false;
// sanity check
if (!deviceNode)
{
return false;
}
// first a simple stat() call
{
return false;
}
else
{
if (isCDROM)
{
{
int fileHandle;
// now try to open the device
if (fileHandle >= 0)
{
// this call will finally reveal the whole truth
#ifdef RT_OS_LINUX
#else
#endif
{
retValue = true;
}
}
}
} else
{
// floppy case
{
/// @todo do some more testing, maybe a nice IOCTL!
retValue = true;
}
}
}
return retValue;
}
#endif // RT_OS_SOLARIS
#ifdef VBOX_WITH_USB
/**
* Checks for the presence and status of the USB Proxy Service.
* Returns S_OK when the Proxy is present and OK, VBOX_E_HOST_ERROR (as a
* warning) if the proxy service is not available due to the way the host is
* available on a Linux host) or E_FAIL and a corresponding error message
* otherwise. Intended to be used by methods that rely on the Proxy Service
* availability.
*
* @note This method may return a warning result code. It is recommended to use
* MultiError to store the return value.
*
* @note Locks this object for reading.
*/
{
AutoCaller autoCaller(this);
if (!m->pUSBProxyService->isActive())
{
/* disable the USB controller completely to avoid assertions if the
* USB proxy service could not start. */
switch (m->pUSBProxyService->getLastError())
{
case VERR_FILE_NOT_FOUND: /** @todo what does this mean? */
return setWarning(E_FAIL,
tr("Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer"));
return setWarning(E_FAIL,
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"));
return setWarning(E_FAIL,
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"));
case VINF_SUCCESS:
return setWarning(E_FAIL,
tr("The USB Proxy Service has not yet been ported to this host"));
default:
tr ("Could not load the Host USB Proxy service"),
m->pUSBProxyService->getLastError());
}
}
return S_OK;
}
#endif /* VBOX_WITH_USB */
{
#ifdef VBOX_WITH_HOSTNETIF_API
if (rc)
{
return E_FAIL;
}
/* Make a copy as the original may be partially destroyed later. */
# ifdef VBOX_WITH_RESOURCE_USAGE_API
# endif
{
bool fGone = true;
{
{
fGone = false;
break;
}
}
if (fGone)
{
# ifdef VBOX_WITH_RESOURCE_USAGE_API
# endif
}
}
/*
* Need to set the references to VirtualBox object in all interface objects
* (see @bugref{6439}).
*/
/* At this point listCopy will contain newly discovered interfaces only. */
{
{
Bstr n;
}
else if (t == HostNetworkInterfaceType_Bridged)
{
# ifdef VBOX_WITH_RESOURCE_USAGE_API
# endif
}
}
return S_OK;
#else
return E_NOTIMPL;
#endif
}
#ifdef VBOX_WITH_RESOURCE_USAGE_API
{
/* Create sub metrics */
//Utf8StrFmt fsNameBase("Filesystem/[root]/Usage");
"Root file system size.");
"Root file system space currently occupied.");
"Root file system space currently empty.");
fsNameBase, "/",
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
/* For now we are concerned with the root file system only. */
if (RT_FAILURE(rc))
return;
{
"Percentage of time disk was busy serving I/O requests.");
*it, fsLoadUtil);
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
}
{
"Disk size.");
*it, fsUsageTotal);
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
}
}
{
/* Create sub metrics */
"Percentage of processor time spent in user mode.");
"Percentage of processor time spent in kernel mode.");
"Percentage of processor time spent idling.");
"Average of current frequency of all processors.");
"Total physical memory installed.");
"Physical memory currently occupied.");
"Physical memory currently available to applications.");
"Total physical memory used by the hypervisor.");
"Total physical memory free inside the hypervisor.");
"Total physical memory ballooned by the hypervisor.");
"Total physical memory shared between VMs.");
/* Create and register base metrics */
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
new pm::AggregateAvg()));
new pm::AggregateMin()));
new pm::AggregateMax()));
}
{
aCollector->unregisterMetricsFor(this);
aCollector->unregisterBaseMetricsFor(this);
}
#endif /* VBOX_WITH_RESOURCE_USAGE_API */
/* static */
{
/*
* Our strategy is as follows: the first three bytes are our fixed
* vendor ID (080027). The remaining 3 bytes will be taken from the
* start of a GUID. This is a fairly safe algorithm.
*/
}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */