summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-server/linux
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-server/linux')
-rw-r--r--src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp233
-rw-r--r--src/VBox/Main/src-server/linux/HostHardwareLinux.cpp5
-rw-r--r--src/VBox/Main/src-server/linux/NetIf-linux.cpp133
-rw-r--r--src/VBox/Main/src-server/linux/PerformanceLinux.cpp336
-rw-r--r--src/VBox/Main/src-server/linux/USBGetDevices.cpp16
-rw-r--r--src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp2
-rw-r--r--src/VBox/Main/src-server/linux/vbox-libhal.cpp2
7 files changed, 616 insertions, 111 deletions
diff --git a/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp b/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp
new file mode 100644
index 00000000..89de18df
--- /dev/null
+++ b/src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp
@@ -0,0 +1,233 @@
+/* $Id: HostDnsServiceLinux.cpp $ */
+/** @file
+ * Linux specific DNS information fetching.
+ */
+
+/*
+ * Copyright (C) 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;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * 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.
+ */
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/initterm.h>
+#include <iprt/file.h>
+#include <iprt/log.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+
+#include <linux/limits.h>
+
+#include <sys/inotify.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <string>
+#include <vector>
+#include "../HostDnsService.h"
+
+
+static int g_DnsMonitorStop[2];
+
+static const std::string g_EtcFolder = "/etc";
+static const std::string g_ResolvConf = "resolv.conf";
+static const std::string g_ResolvConfFullPath = "/etc/resolv.conf";
+
+class FileDescriptor
+{
+ public:
+ FileDescriptor(int d = -1):fd(d){}
+
+ virtual ~FileDescriptor() {
+ if (fd != -1)
+ close(fd);
+ }
+
+ int fileDescriptor() const {return fd;}
+
+ protected:
+ int fd;
+};
+
+
+class AutoNotify:public FileDescriptor
+{
+ public:
+ AutoNotify()
+ {
+ FileDescriptor::fd = inotify_init();
+ AssertReturnVoid(FileDescriptor::fd != -1);
+ }
+};
+
+struct InotifyEventWithName
+{
+ struct inotify_event e;
+ char name[NAME_MAX];
+};
+
+HostDnsServiceLinux::~HostDnsServiceLinux()
+{
+ monitorThreadShutdown();
+}
+
+
+int HostDnsServiceLinux::monitorWorker()
+{
+
+ AutoNotify a;
+
+ int rc = socketpair(AF_LOCAL, SOCK_DGRAM, 0, g_DnsMonitorStop);
+ AssertMsgReturn(rc == 0, ("socketpair: failed (%d: %s)\n", errno, strerror(errno)), E_FAIL);
+
+ FileDescriptor stopper0(g_DnsMonitorStop[0]);
+ FileDescriptor stopper1(g_DnsMonitorStop[1]);
+
+ pollfd polls[2];
+ RT_ZERO(polls);
+
+ polls[0].fd = a.fileDescriptor();
+ polls[0].events = POLLIN;
+
+ polls[1].fd = g_DnsMonitorStop[1];
+ polls[1].events = POLLIN;
+
+ monitorThreadInitializationDone();
+
+ int wd[2];
+ wd[0] = wd[1] = -1;
+ /* inotify inialization */
+ wd[0] = inotify_add_watch(a.fileDescriptor(),
+ g_ResolvConfFullPath.c_str(), IN_CLOSE_WRITE|IN_DELETE_SELF);
+
+ /**
+ * If /etc/resolv.conf exists we want to listen for movements: because
+ * # mv /etc/resolv.conf ...
+ * won't arm IN_DELETE_SELF on wd[0] instead it will fire IN_MOVE_FROM on wd[1].
+ *
+ * Because on some distributions /etc/resolv.conf is link, wd[0] can't detect deletion,
+ * it's recognizible on directory level (wd[1]) only.
+ */
+ wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
+ wd[0] == -1 ? IN_MOVED_TO|IN_CREATE : IN_MOVED_FROM|IN_DELETE);
+
+ struct InotifyEventWithName combo;
+ while(true)
+ {
+ rc = poll(polls, 2, -1);
+ if (rc == -1)
+ continue;
+
+ AssertMsgReturn( ((polls[0].revents & (POLLERR|POLLNVAL)) == 0)
+ && ((polls[1].revents & (POLLERR|POLLNVAL)) == 0),
+ ("Debug Me"), VERR_INTERNAL_ERROR);
+
+ if (polls[1].revents & POLLIN)
+ return VINF_SUCCESS; /* time to shutdown */
+
+ if (polls[0].revents & POLLIN)
+ {
+ RT_ZERO(combo);
+ ssize_t r = read(polls[0].fd, static_cast<void *>(&combo), sizeof(combo));
+
+ if (combo.e.wd == wd[0])
+ {
+ if (combo.e.mask & IN_CLOSE_WRITE)
+ {
+ readResolvConf();
+ /* notifyAll() takes required locks */
+ notifyAll();
+ }
+ else if (combo.e.mask & IN_DELETE_SELF)
+ {
+ inotify_rm_watch(a.fileDescriptor(), wd[0]); /* removes file watcher */
+ inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
+ IN_MOVED_TO|IN_CREATE); /* alter folder watcher */
+ }
+ else if (combo.e.mask & IN_IGNORED)
+ {
+ wd[0] = -1; /* we want receive any events on this watch */
+ }
+ else
+ {
+ /**
+ * It shouldn't happen, in release we will just ignore in debug
+ * we will have to chance to look at into inotify_event
+ */
+ AssertMsgFailed(("Debug Me!!!"));
+ }
+ }
+ else if (combo.e.wd == wd[1])
+ {
+ if ( combo.e.mask & IN_MOVED_FROM
+ || combo.e.mask & IN_DELETE)
+ {
+ if (g_ResolvConf == combo.e.name)
+ {
+ /**
+ * Our file has been moved so we should change watching mode.
+ */
+ inotify_rm_watch(a.fileDescriptor(), wd[0]);
+ wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
+ IN_MOVED_TO|IN_CREATE);
+ AssertMsg(wd[1] != -1,
+ ("It shouldn't happen, further investigation is needed\n"));
+ }
+ }
+ else
+ {
+ AssertMsg(combo.e.mask & (IN_MOVED_TO|IN_CREATE),
+ ("%RX32 event isn't expected, we are waiting for IN_MOVED|IN_CREATE\n",
+ combo.e.mask));
+ if (g_ResolvConf == combo.e.name)
+ {
+ AssertMsg(wd[0] == -1, ("We haven't removed file watcher first\n"));
+
+ /* alter folder watcher*/
+ wd[1] = inotify_add_watch(a.fileDescriptor(), g_EtcFolder.c_str(),
+ IN_MOVED_FROM|IN_DELETE);
+ AssertMsg(wd[1] != -1, ("It shouldn't happen.\n"));
+
+ wd[0] = inotify_add_watch(a.fileDescriptor(),
+ g_ResolvConfFullPath.c_str(),
+ IN_CLOSE_WRITE | IN_DELETE_SELF);
+ AssertMsg(wd[0] != -1, ("Adding watcher to file (%s) has been failed!\n",
+ g_ResolvConfFullPath.c_str()));
+
+ /* Notify our listeners */
+ readResolvConf();
+ notifyAll();
+
+ }
+ }
+ }
+ else
+ {
+ /* It shouldn't happen */
+ AssertMsgFailed(("Shouldn't happen! Please debug me!"));
+ }
+ }
+ }
+}
+
+
+void HostDnsServiceLinux::monitorThreadShutdown()
+{
+ send(g_DnsMonitorStop[0], "", 1, 0);
+}
diff --git a/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp b/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp
index 2dc722cc..1ff26d81 100644
--- a/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp
+++ b/src/VBox/Main/src-server/linux/HostHardwareLinux.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2008-2010 Oracle Corporation
+ * Copyright (C) 2008-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;
@@ -37,7 +37,6 @@
#include <iprt/param.h>
#include <iprt/path.h>
#include <iprt/string.h>
-#include <iprt/thread.h> /* for RTThreadSleep() */
#include <linux/cdrom.h>
#include <linux/fd.h>
@@ -1282,7 +1281,7 @@ hotplugInotifyImpl::hotplugInotifyImpl(const char *pcszDevicesRoot) :
break;
if (RT_FAILURE(rc = pipeCreateSimple(&mhWakeupPipeR, &mhWakeupPipeW)))
break;
- } while(0);
+ } while (0);
mStatus = rc;
if (RT_FAILURE(rc))
term();
diff --git a/src/VBox/Main/src-server/linux/NetIf-linux.cpp b/src/VBox/Main/src-server/linux/NetIf-linux.cpp
index 6fe799cf..2384cc52 100644
--- a/src/VBox/Main/src-server/linux/NetIf-linux.cpp
+++ b/src/VBox/Main/src-server/linux/NetIf-linux.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -37,14 +37,23 @@
#include "netif.h"
#include "Logging.h"
+/**
+ * Obtain the name of the interface used for default routing.
+ *
+ * NOTE: There is a copy in Devices/Network/testcase/tstIntNet-1.cpp.
+ *
+ * @returns VBox status code.
+ *
+ * @param pszName The buffer of IFNAMSIZ+1 length where to put the name.
+ */
static int getDefaultIfaceName(char *pszName)
{
FILE *fp = fopen("/proc/net/route", "r");
char szBuf[1024];
char szIfName[17];
- char szAddr[129];
- char szGateway[129];
- char szMask[129];
+ uint32_t uAddr;
+ uint32_t uGateway;
+ uint32_t uMask;
int iTmp;
unsigned uFlags;
@@ -52,13 +61,13 @@ static int getDefaultIfaceName(char *pszName)
{
while (fgets(szBuf, sizeof(szBuf)-1, fp))
{
- int n = sscanf(szBuf, "%16s %128s %128s %X %d %d %d %128s %d %d %d\n",
- szIfName, szAddr, szGateway, &uFlags, &iTmp, &iTmp, &iTmp,
- szMask, &iTmp, &iTmp, &iTmp);
+ int n = sscanf(szBuf, "%16s %x %x %x %d %d %d %x %d %d %d\n",
+ szIfName, &uAddr, &uGateway, &uFlags, &iTmp, &iTmp, &iTmp,
+ &uMask, &iTmp, &iTmp, &iTmp);
if (n < 10 || !(uFlags & RTF_UP))
continue;
- if (strcmp(szAddr, "00000000") == 0 && strcmp(szMask, "00000000") == 0)
+ if (uAddr == 0 && uMask == 0)
{
fclose(fp);
strncpy(pszName, szIfName, 16);
@@ -71,14 +80,55 @@ static int getDefaultIfaceName(char *pszName)
return VERR_INTERNAL_ERROR;
}
+static uint32_t getInterfaceSpeed(const char *pszName)
+{
+ /*
+ * I wish I could do simple ioctl here, but older kernels require root
+ * privileges for any ethtool commands.
+ */
+ char szBuf[256];
+ uint32_t uSpeed = 0;
+ /* First, we try to retrieve the speed via sysfs. */
+ RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
+ FILE *fp = fopen(szBuf, "r");
+ if (fp)
+ {
+ if (fscanf(fp, "%u", &uSpeed) != 1)
+ uSpeed = 0;
+ fclose(fp);
+ }
+ if (uSpeed == 10)
+ {
+ /* Check the cable is plugged in at all */
+ unsigned uCarrier = 0;
+ RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/carrier", pszName);
+ fp = fopen(szBuf, "r");
+ if (fp)
+ {
+ if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0)
+ uSpeed = 0;
+ fclose(fp);
+ }
+ }
+
+ if (uSpeed == 0)
+ {
+ /* Failed to get speed via sysfs, go to plan B. */
+ int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
+ if (RT_SUCCESS(rc))
+ uSpeed = RTStrToUInt32(szBuf);
+ }
+ return uSpeed;
+}
+
static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
{
// Zeroing out pInfo is a bad idea as it should contain both short and long names at
// this point. So make sure the structure is cleared by the caller if necessary!
// memset(pInfo, 0, sizeof(*pInfo));
struct ifreq Req;
- memset(&Req, 0, sizeof(Req));
- strncpy(Req.ifr_name, pszName, sizeof(Req.ifr_name) - 1);
+ RT_ZERO(Req);
+ RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pszName);
if (ioctl(iSocket, SIOCGIFHWADDR, &Req) >= 0)
{
switch (Req.ifr_hwaddr.sa_family)
@@ -122,7 +172,7 @@ static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
char szName[30];
for (;;)
{
- memset(szName, 0, sizeof(szName));
+ RT_ZERO(szName);
int n = fscanf(fp,
"%08x%08x%08x%08x"
" %02x %02x %02x %02x %20s\n",
@@ -152,31 +202,10 @@ static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
* Don't even try to get speed for non-Ethernet interfaces, it only
* produces errors.
*/
- pInfo->uSpeedMbits = 0;
if (pInfo->enmMediumType == NETIF_T_ETHERNET)
- {
- /*
- * I wish I could do simple ioctl here, but older kernels require root
- * privileges for any ethtool commands.
- */
- char szBuf[256];
- /* First, we try to retrieve the speed via sysfs. */
- RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
- fp = fopen(szBuf, "r");
- if (fp)
- {
- if (fscanf(fp, "%u", &pInfo->uSpeedMbits) != 1)
- pInfo->uSpeedMbits = 0;
- fclose(fp);
- }
- if (pInfo->uSpeedMbits == 0)
- {
- /* Failed to get speed via sysfs, go to plan B. */
- int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
- if (RT_SUCCESS(rc))
- pInfo->uSpeedMbits = RTStrToUInt32(szBuf);
- }
- }
+ pInfo->uSpeedMbits = getInterfaceSpeed(pszName);
+ else
+ pInfo->uSpeedMbits = 0;
}
return VINF_SUCCESS;
}
@@ -216,7 +245,7 @@ int NetIfList(std::list <ComObjPtr<HostNetworkInterface> > &list)
IfObj.createObject();
HostNetworkInterfaceType_T enmType;
- if (strncmp("vboxnet", pszName, 7))
+ if (strncmp(pszName, RT_STR_TUPLE("vboxnet")))
enmType = HostNetworkInterfaceType_Bridged;
else
enmType = HostNetworkInterfaceType_HostOnly;
@@ -251,3 +280,35 @@ int NetIfGetConfigByName(PNETIFINFO pInfo)
close(sock);
return rc;
}
+
+/**
+ * Retrieve the physical link speed in megabits per second. If the interface is
+ * not up or otherwise unavailable the zero speed is returned.
+ *
+ * @returns VBox status code.
+ *
+ * @param pcszIfName Interface name.
+ * @param puMbits Where to store the link speed.
+ */
+int NetIfGetLinkSpeed(const char *pcszIfName, uint32_t *puMbits)
+{
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return VERR_OUT_OF_RESOURCES;
+ struct ifreq Req;
+ RT_ZERO(Req);
+ RTStrCopy(Req.ifr_name, sizeof(Req.ifr_name), pcszIfName);
+ if (ioctl(sock, SIOCGIFHWADDR, &Req) >= 0)
+ {
+ if (ioctl(sock, SIOCGIFFLAGS, &Req) >= 0)
+ if (Req.ifr_flags & IFF_UP)
+ {
+ close(sock);
+ *puMbits = getInterfaceSpeed(pcszIfName);
+ return VINF_SUCCESS;
+ }
+ }
+ close(sock);
+ *puMbits = 0;
+ return VWRN_NOT_FOUND;
+}
diff --git a/src/VBox/Main/src-server/linux/PerformanceLinux.cpp b/src/VBox/Main/src-server/linux/PerformanceLinux.cpp
index 4e165ee3..77ccb9b8 100644
--- a/src/VBox/Main/src-server/linux/PerformanceLinux.cpp
+++ b/src/VBox/Main/src-server/linux/PerformanceLinux.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2008-2011 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -27,8 +27,11 @@
#include <iprt/ctype.h>
#include <iprt/err.h>
#include <iprt/param.h>
+#include <iprt/path.h>
#include <iprt/string.h>
+#include <iprt/system.h>
#include <iprt/mp.h>
+#include <iprt/linux/sysfs.h>
#include <map>
#include <vector>
@@ -36,6 +39,8 @@
#include "Logging.h"
#include "Performance.h"
+#define VBOXVOLINFO_NAME "VBoxVolInfo"
+
namespace pm {
class CollectorLinux : public CollectorHAL
@@ -45,15 +50,23 @@ public:
virtual int preCollect(const CollectorHints& hints, uint64_t /* iTick */);
virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available);
virtual int getHostFilesystemUsage(const char *name, ULONG *total, ULONG *used, ULONG *available);
+ virtual int getHostDiskSize(const char *name, uint64_t *size);
virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used);
virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
virtual int getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx);
virtual int getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms);
virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
+
+ virtual int getDiskListByFs(const char *name, DiskList& listUsage, DiskList& listLoad);
private:
virtual int _getRawHostCpuLoad();
int getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uint64_t *cpuKernel, ULONG *memPagesUsed);
+ void getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName, bool fTrimDigits);
+ void addVolumeDependencies(const char *pcszVolume, DiskList& listDisks);
+ void addRaidDisks(const char *pcszDevice, DiskList& listDisks);
+ char *trimTrailingDigits(char *pszName);
+ char *trimNewline(char *pszName);
struct VMProcessStats
{
@@ -68,6 +81,7 @@ private:
uint64_t mUser, mKernel, mIdle;
uint64_t mSingleUser, mSingleKernel, mSingleIdle;
uint32_t mHZ;
+ ULONG totalRAM;
};
CollectorHAL *createHAL()
@@ -88,6 +102,13 @@ CollectorLinux::CollectorLinux()
else
mHZ = hz;
LogFlowThisFunc(("mHZ=%u\n", mHZ));
+
+ uint64_t cb;
+ int rc = RTSystemQueryTotalRam(&cb);
+ if (RT_FAILURE(rc))
+ totalRAM = 0;
+ else
+ totalRAM = (ULONG)(cb / 1024);
}
int CollectorLinux::preCollect(const CollectorHints& hints, uint64_t /* iTick */)
@@ -190,35 +211,21 @@ int CollectorLinux::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint
int CollectorLinux::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
{
- int rc = VINF_SUCCESS;
- ULONG buffers, cached;
- FILE *f = fopen("/proc/meminfo", "r");
-
- if (f)
+ AssertReturn(totalRAM, VERR_INTERNAL_ERROR);
+ uint64_t cb;
+ int rc = RTSystemQueryAvailableRam(&cb);
+ if (RT_SUCCESS(rc))
{
- int processed = fscanf(f, "MemTotal: %u kB\n", total);
- processed += fscanf(f, "MemFree: %u kB\n", available);
- processed += fscanf(f, "Buffers: %u kB\n", &buffers);
- processed += fscanf(f, "Cached: %u kB\n", &cached);
- if (processed == 4)
- {
- *available += buffers + cached;
- *used = *total - *available;
- }
- else
- rc = VERR_FILE_IO_ERROR;
- fclose(f);
+ *total = totalRAM;
+ *available = cb / 1024;
+ *used = *total - *available;
}
- else
- rc = VERR_ACCESS_DENIED;
-
return rc;
}
int CollectorLinux::getHostFilesystemUsage(const char *path, ULONG *total, ULONG *used, ULONG *available)
{
struct statvfs stats;
- const unsigned _MB = 1024 * 1024;
if (statvfs(path, &stats) == -1)
{
@@ -226,13 +233,35 @@ int CollectorLinux::getHostFilesystemUsage(const char *path, ULONG *total, ULONG
return VERR_ACCESS_DENIED;
}
uint64_t cbBlock = stats.f_frsize ? stats.f_frsize : stats.f_bsize;
- *total = (ULONG)(cbBlock * stats.f_blocks / _MB);
- *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _MB);
- *available = (ULONG)(cbBlock * stats.f_bavail / _MB);
+ *total = (ULONG)(cbBlock * stats.f_blocks / _1M);
+ *used = (ULONG)(cbBlock * (stats.f_blocks - stats.f_bfree) / _1M);
+ *available = (ULONG)(cbBlock * stats.f_bavail / _1M);
return VINF_SUCCESS;
}
+int CollectorLinux::getHostDiskSize(const char *pszFile, uint64_t *size)
+{
+ char *pszPath = NULL;
+
+ RTStrAPrintf(&pszPath, "/sys/block/%s/size", pszFile);
+ Assert(pszPath);
+
+ int rc = VINF_SUCCESS;
+ if (!RTLinuxSysFsExists(pszPath))
+ rc = VERR_FILE_NOT_FOUND;
+ else
+ {
+ int64_t cSize = RTLinuxSysFsReadIntFile(0, pszPath);
+ if (cSize < 0)
+ rc = VERR_ACCESS_DENIED;
+ else
+ *size = cSize * 512;
+ }
+ RTStrFree(pszPath);
+ return rc;
+}
+
int CollectorLinux::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
{
VMProcessMap::const_iterator it = mProcessStats.find(process);
@@ -261,9 +290,8 @@ int CollectorLinux::getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uin
char buf[80]; /* @todo: this should be tied to max allowed proc name. */
RTStrAPrintf(&pszName, "/proc/%d/stat", process);
- //printf("Opening %s...\n", pszName);
FILE *f = fopen(pszName, "r");
- RTMemFree(pszName);
+ RTStrFree(pszName);
if (f)
{
@@ -288,42 +316,35 @@ int CollectorLinux::getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uin
return rc;
}
-int CollectorLinux::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx)
+int CollectorLinux::getRawHostNetworkLoad(const char *pszFile, uint64_t *rx, uint64_t *tx)
{
- int rc = VINF_SUCCESS;
char szIfName[/*IFNAMSIZ*/ 16 + 36];
- long long unsigned int u64Rx, u64Tx;
- RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/rx_bytes", name);
- FILE *f = fopen(szIfName, "r");
- if (f)
- {
- if (fscanf(f, "%llu", &u64Rx) == 1)
- *rx = u64Rx;
- else
- rc = VERR_FILE_IO_ERROR;
- fclose(f);
- RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/tx_bytes", name);
- f = fopen(szIfName, "r");
- if (f)
- {
- if (fscanf(f, "%llu", &u64Tx) == 1)
- *tx = u64Tx;
- else
- rc = VERR_FILE_IO_ERROR;
- fclose(f);
- }
- else
- rc = VERR_ACCESS_DENIED;
- }
- else
- rc = VERR_ACCESS_DENIED;
+ RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/rx_bytes", pszFile);
+ if (!RTLinuxSysFsExists(szIfName))
+ return VERR_FILE_NOT_FOUND;
- return rc;
+ int64_t cSize = RTLinuxSysFsReadIntFile(0, szIfName);
+ if (cSize < 0)
+ return VERR_ACCESS_DENIED;
+
+ *rx = cSize;
+
+ RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/tx_bytes", pszFile);
+ if (!RTLinuxSysFsExists(szIfName))
+ return VERR_FILE_NOT_FOUND;
+
+ cSize = RTLinuxSysFsReadIntFile(0, szIfName);
+ if (cSize < 0)
+ return VERR_ACCESS_DENIED;
+
+ *tx = cSize;
+ return VINF_SUCCESS;
}
int CollectorLinux::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint64_t *total_ms)
{
+#if 0
int rc = VINF_SUCCESS;
char szIfName[/*IFNAMSIZ*/ 16 + 36];
long long unsigned int u64Busy, tmp;
@@ -344,28 +365,184 @@ int CollectorLinux::getRawHostDiskLoad(const char *name, uint64_t *disk_ms, uint
}
else
rc = VERR_ACCESS_DENIED;
+#else
+ int rc = VERR_MISSING;
+ FILE *f = fopen("/proc/diskstats", "r");
+ if (f)
+ {
+ char szBuf[128];
+ while (fgets(szBuf, sizeof(szBuf), f))
+ {
+ char *pszBufName = szBuf;
+ while (*pszBufName == ' ') ++pszBufName; /* Skip spaces */
+ while (RT_C_IS_DIGIT(*pszBufName)) ++pszBufName; /* Skip major */
+ while (*pszBufName == ' ') ++pszBufName; /* Skip spaces */
+ while (RT_C_IS_DIGIT(*pszBufName)) ++pszBufName; /* Skip minor */
+ while (*pszBufName == ' ') ++pszBufName; /* Skip spaces */
+
+ char *pszBufData = strchr(pszBufName, ' ');
+ if (!pszBufData)
+ {
+ LogRel(("CollectorLinux::getRawHostDiskLoad() failed to parse disk stats: %s\n", szBuf));
+ continue;
+ }
+ *pszBufData++ = '\0';
+ if (!strcmp(name, pszBufName))
+ {
+ long long unsigned int u64Busy, tmp;
+
+ if (sscanf(pszBufData, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
+ &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &tmp, &u64Busy, &tmp) == 11)
+ {
+ *disk_ms = u64Busy;
+ *total_ms = (uint64_t)(mSingleUser + mSingleKernel + mSingleIdle) * 1000 / mHZ;
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_FILE_IO_ERROR;
+ break;
+ }
+ }
+ fclose(f);
+ }
+#endif
return rc;
}
-static char *getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName)
+char *CollectorLinux::trimNewline(char *pszName)
+{
+ unsigned cbName = strlen(pszName);
+ if (cbName == 0)
+ return pszName;
+
+ char *pszEnd = pszName + cbName - 1;
+ while (pszEnd > pszName && *pszEnd == '\n')
+ pszEnd--;
+ pszEnd[1] = '\0';
+
+ return pszName;
+}
+
+char *CollectorLinux::trimTrailingDigits(char *pszName)
+{
+ unsigned cbName = strlen(pszName);
+ if (cbName == 0)
+ return pszName;
+
+ char *pszEnd = pszName + cbName - 1;
+ while (pszEnd > pszName && (RT_C_IS_DIGIT(*pszEnd) || *pszEnd == '\n'))
+ pszEnd--;
+ pszEnd[1] = '\0';
+
+ return pszName;
+}
+
+/**
+ * Use the partition name to get the name of the disk. Any path component is stripped.
+ * if fTrimDigits is true, trailing digits are stripped as well, for example '/dev/sda5'
+ * is converted to 'sda'.
+ *
+ * @param pszDiskName Where to store the name of the disk.
+ * @param cbDiskName The size of the buffer pszDiskName points to.
+ * @param pszDevName The device name used to get the disk name.
+ * @param fTrimDigits Trim trailing digits (e.g. /dev/sda5)
+ */
+void CollectorLinux::getDiskName(char *pszDiskName, size_t cbDiskName, const char *pszDevName, bool fTrimDigits)
{
unsigned cbName = 0;
unsigned cbDevName = strlen(pszDevName);
const char *pszEnd = pszDevName + cbDevName - 1;
- while (pszEnd > pszDevName && RT_C_IS_DIGIT(*pszEnd))
- pszEnd--;
+ if (fTrimDigits)
+ while (pszEnd > pszDevName && RT_C_IS_DIGIT(*pszEnd))
+ pszEnd--;
while (pszEnd > pszDevName && *pszEnd != '/')
{
cbName++;
pszEnd--;
}
RTStrCopy(pszDiskName, RT_MIN(cbName + 1, cbDiskName), pszEnd + 1);
- return pszDiskName;
}
+void CollectorLinux::addRaidDisks(const char *pcszDevice, DiskList& listDisks)
+{
+ FILE *f = fopen("/proc/mdstat", "r");
+ if (f)
+ {
+ char szBuf[128];
+ while (fgets(szBuf, sizeof(szBuf), f))
+ {
+ char *pszBufName = szBuf;
-int getDiskListByFs(const char *pszPath, DiskList& listDisks)
+ char *pszBufData = strchr(pszBufName, ' ');
+ if (!pszBufData)
+ {
+ LogRel(("CollectorLinux::addRaidDisks() failed to parse disk stats: %s\n", szBuf));
+ continue;
+ }
+ *pszBufData++ = '\0';
+ if (!strcmp(pcszDevice, pszBufName))
+ {
+ while (*pszBufData == ':') ++pszBufData; /* Skip delimiter */
+ while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */
+ while (RT_C_IS_ALNUM(*pszBufData)) ++pszBufData; /* Skip status */
+ while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */
+ while (RT_C_IS_ALNUM(*pszBufData)) ++pszBufData; /* Skip type */
+
+ while (*pszBufData != '\0')
+ {
+ while (*pszBufData == ' ') ++pszBufData; /* Skip spaces */
+ char *pszDisk = pszBufData;
+ while (RT_C_IS_ALPHA(*pszBufData))
+ ++pszBufData;
+ if (*pszBufData)
+ {
+ *pszBufData++ = '\0';
+ listDisks.push_back(RTCString(pszDisk));
+ while (*pszBufData != '\0' && *pszBufData != ' ')
+ ++pszBufData;
+ }
+ else
+ listDisks.push_back(RTCString(pszDisk));
+ }
+ break;
+ }
+ }
+ fclose(f);
+ }
+}
+
+void CollectorLinux::addVolumeDependencies(const char *pcszVolume, DiskList& listDisks)
+{
+ char szVolInfo[RTPATH_MAX];
+ int rc = RTPathAppPrivateArch(szVolInfo,
+ sizeof(szVolInfo) - sizeof("/" VBOXVOLINFO_NAME " ") - strlen(pcszVolume));
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("VolInfo: Failed to get program path, rc=%Rrc\n", rc));
+ return;
+ }
+ strcat(szVolInfo, "/" VBOXVOLINFO_NAME " ");
+ strcat(szVolInfo, pcszVolume);
+
+ FILE *fp = popen(szVolInfo, "r");
+ if (fp)
+ {
+ char szBuf[128];
+
+ while (fgets(szBuf, sizeof(szBuf), fp))
+ if (strncmp(szBuf, RT_STR_TUPLE("dm-")))
+ listDisks.push_back(RTCString(trimTrailingDigits(szBuf)));
+ else
+ listDisks.push_back(RTCString(trimNewline(szBuf)));
+
+ pclose(fp);
+ }
+ else
+ listDisks.push_back(RTCString(pcszVolume));
+}
+
+int CollectorLinux::getDiskListByFs(const char *pszPath, DiskList& listUsage, DiskList& listLoad)
{
FILE *mtab = setmntent("/etc/mtab", "r");
if (mtab)
@@ -373,10 +550,45 @@ int getDiskListByFs(const char *pszPath, DiskList& listDisks)
struct mntent *mntent;
while ((mntent = getmntent(mtab)))
{
+ /* Skip rootfs entry, there must be another root mount. */
+ if (strcmp(mntent->mnt_fsname, "rootfs") == 0)
+ continue;
if (strcmp(pszPath, mntent->mnt_dir) == 0)
{
- char szDevName[32];
- listDisks.push_back(RTCString(getDiskName(szDevName, sizeof(szDevName), mntent->mnt_fsname)));
+ char szDevName[128];
+ char szFsName[1024];
+ /* Try to resolve symbolic link if necessary. Yes, we access the file system here! */
+ int rc = RTPathReal(mntent->mnt_fsname, szFsName, sizeof(szFsName));
+ if (RT_FAILURE(rc))
+ continue; /* something got wrong, just ignore this path */
+ /* check against the actual mtab entry, NOT the real path as /dev/mapper/xyz is
+ * often a symlink to something else */
+ if (!strncmp(mntent->mnt_fsname, RT_STR_TUPLE("/dev/mapper")))
+ {
+ /* LVM */
+ getDiskName(szDevName, sizeof(szDevName), mntent->mnt_fsname, false /*=fTrimDigits*/);
+ addVolumeDependencies(szDevName, listUsage);
+ listLoad = listUsage;
+ }
+ else if (!strncmp(szFsName, RT_STR_TUPLE("/dev/md")))
+ {
+ /* Software RAID */
+ getDiskName(szDevName, sizeof(szDevName), szFsName, false /*=fTrimDigits*/);
+ listUsage.push_back(RTCString(szDevName));
+ addRaidDisks(szDevName, listLoad);
+ }
+ else
+ {
+ /* Plain disk partition. Trim the trailing digits to get the drive name */
+ getDiskName(szDevName, sizeof(szDevName), szFsName, true /*=fTrimDigits*/);
+ listUsage.push_back(RTCString(szDevName));
+ listLoad.push_back(RTCString(szDevName));
+ }
+ if (listUsage.empty() || listLoad.empty())
+ {
+ LogRel(("Failed to retrive disk info: getDiskName(%s) --> %s\n",
+ mntent->mnt_fsname, szDevName));
+ }
break;
}
}
diff --git a/src/VBox/Main/src-server/linux/USBGetDevices.cpp b/src/VBox/Main/src-server/linux/USBGetDevices.cpp
index d824a017..b4ef0df7 100644
--- a/src/VBox/Main/src-server/linux/USBGetDevices.cpp
+++ b/src/VBox/Main/src-server/linux/USBGetDevices.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -357,11 +357,11 @@ static int usbReadSpeed(const char *pszValue, USBDEVICESPEED *pSpd, char **ppszN
{
pszValue = RTStrStripL(pszValue);
/* verified with Linux 2.4.0 ... Linux 2.6.25 */
- if (!strncmp(pszValue, "1.5", 3))
+ if (!strncmp(pszValue, RT_STR_TUPLE("1.5")))
*pSpd = USBDEVICESPEED_LOW;
- else if (!strncmp(pszValue, "12 ", 3))
+ else if (!strncmp(pszValue, RT_STR_TUPLE("12 ")))
*pSpd = USBDEVICESPEED_FULL;
- else if (!strncmp(pszValue, "480", 3))
+ else if (!strncmp(pszValue, RT_STR_TUPLE("480")))
*pSpd = USBDEVICESPEED_HIGH;
else
*pSpd = USBDEVICESPEED_UNKNOWN;
@@ -593,7 +593,7 @@ static PUSBDEVICE getDevicesFromUsbfs(const char *pcszUsbfsRoot, bool testfs)
deviceFreeMembers(&Dev);
/* Reset device state */
- memset(&Dev, 0, sizeof (Dev));
+ RT_ZERO(Dev);
Dev.enmState = USBDEVICESTATE_UNUSED;
cHits = 1;
@@ -1122,7 +1122,7 @@ static int usbGetPortFromSysfsPath(const char *pszPath, uint8_t *pu8Port)
if (!pchDash && !pchDot)
{
/* No -/. so it must be a root hub. Check that it's usb<something>. */
- if (strncmp(pszLastComp, "usb", sizeof("usb") - 1) != 0)
+ if (strncmp(pszLastComp, RT_STR_TUPLE("usb")) != 0)
{
Log(("usbGetPortFromSysfsPath(%s): failed [2]\n", pszPath));
return VERR_INVALID_PARAMETER;
@@ -1430,7 +1430,7 @@ void TestUSBSetInotifyAvailable(bool fHaveInotifyLibC, bool fHaveInotifyKernel)
s_fHaveInotifyKernel = fHaveInotifyKernel;
}
# define dlsym testDLSym
-# define close(a) do {} while(0)
+# define close(a) do {} while (0)
#endif
/** Is inotify available and working on this system? This is a requirement
@@ -1586,7 +1586,7 @@ void TestUSBSetEnv(const char *pcszEnvUsb, const char *pcszEnvUsbRoot)
* what is available on the host and what if anything the user has specified
* in the environment.
* @returns iprt status value
- * @param pfUsingUsbfsDevices on success this will be set to true if
+ * @param pfUsingUsbfsDevices on success this will be set to true if
* the prefered access method is USBFS-like and to
* false if it is sysfs/device node-like
* @param ppcszDevicesRoot on success the root of the tree of USBFS-like
diff --git a/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp b/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp
index a89c3e00..82c97aa9 100644
--- a/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp
+++ b/src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp
@@ -320,7 +320,7 @@ int USBProxyServiceLinux::waitUsbfs(RTMSINTERVAL aMillies)
aMillies = 500;
}
- memset(&PollFds, 0, sizeof(PollFds));
+ RT_ZERO(PollFds);
PollFds[0].fd = RTFileToNative(mhFile);
PollFds[0].events = POLLIN;
PollFds[1].fd = RTPipeToNative(mhWakeupPipeR);
diff --git a/src/VBox/Main/src-server/linux/vbox-libhal.cpp b/src/VBox/Main/src-server/linux/vbox-libhal.cpp
index 2e7c2716..ade8f072 100644
--- a/src/VBox/Main/src-server/linux/vbox-libhal.cpp
+++ b/src/VBox/Main/src-server/linux/vbox-libhal.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;