diff options
Diffstat (limited to 'src/VBox/Main/src-server/linux')
-rw-r--r-- | src/VBox/Main/src-server/linux/HostDnsServiceLinux.cpp | 233 | ||||
-rw-r--r-- | src/VBox/Main/src-server/linux/HostHardwareLinux.cpp | 5 | ||||
-rw-r--r-- | src/VBox/Main/src-server/linux/NetIf-linux.cpp | 133 | ||||
-rw-r--r-- | src/VBox/Main/src-server/linux/PerformanceLinux.cpp | 336 | ||||
-rw-r--r-- | src/VBox/Main/src-server/linux/USBGetDevices.cpp | 16 | ||||
-rw-r--r-- | src/VBox/Main/src-server/linux/USBProxyServiceLinux.cpp | 2 | ||||
-rw-r--r-- | src/VBox/Main/src-server/linux/vbox-libhal.cpp | 2 |
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; |