From: VMware, Inc <> Date: Wed, 20 Jan 2010 21:24:09 +0000 (-0800) Subject: Remove utilPosix.c from open-vm-tools. X-Git-Tag: 2010.01.19-226760~43 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d5a4c445a25dcb6e0927cebd9530d3e7a3c2ef76;p=thirdparty%2Fopen-vm-tools.git Remove utilPosix.c from open-vm-tools. It's not used by any OVT code and also removes one dependency on lib/lock. Signed-off-by: Marcelo Vanzin --- diff --git a/open-vm-tools/lib/user/Makefile.am b/open-vm-tools/lib/user/Makefile.am index 3482c648e..fab4bda51 100644 --- a/open-vm-tools/lib/user/Makefile.am +++ b/open-vm-tools/lib/user/Makefile.am @@ -19,6 +19,5 @@ noinst_LTLIBRARIES = libUser.la libUser_la_SOURCES = libUser_la_SOURCES += util.c -libUser_la_SOURCES += utilPosix.c AM_CFLAGS = @LIB_USER_CPPFLAGS@ diff --git a/open-vm-tools/lib/user/utilPosix.c b/open-vm-tools/lib/user/utilPosix.c deleted file mode 100644 index 85cdb3b40..000000000 --- a/open-vm-tools/lib/user/utilPosix.c +++ /dev/null @@ -1,1150 +0,0 @@ -/********************************************************* - * Copyright (C) 2004 VMware, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation version 2.1 and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - *********************************************************/ - -/* - * utilPosix.c -- - * - * Posix misc util functions. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !__FreeBSD__ && !sun -# include -#endif - -#ifdef sun -# include -#endif - -#include "vmware.h" -#include "file.h" -#include "util.h" -#include "su.h" -#include "vm_atomic.h" -#include "str.h" -#include "vm_version.h" -#include "random.h" -#include "hostinfo.h" -#include "userlock.h" -#include "escape.h" -#include "unicodeOperations.h" -#include "err.h" -#include "posix.h" -#include "vmstdio.h" - -#define LOGLEVEL_MODULE util -#include "loglevel_user.h" -#define LGPFX "UtilPosix:" - - -/* For Util_GetProcessName() */ -#ifdef sun -# define PROCFILE "psinfo" -#else -# define PROCFILE "status" - /* - * Note that the limit of what is output for the process name in - * /proc//status is 15 characters (30 with '\' -> '\\' escaping) on - * Linux, and 19 characters (76 with ' ' -> '\040' escaping) on FreeBSD. - * Reading in at most 128 gives us a bit of extra room in case these fields - * grow in the future. The 129 in our buffer is for the NUL terminator. - */ -# define PSINFOSZ 129 -# ifdef __linux__ -# define PRE "Name: " -# define POST "\n" -# define PSINFOFMT "%128[^\n]" -# else /* FreeBSD */ -# define PRE -# define POST " " -# define PSINFOFMT "%128s" -# endif -#endif - -#if defined(VMX86_STATS) && defined(__linux__) && !defined(VMX86_SERVER) -#define SYS_CSTATE_DIR "/sys/devices/system/cpu" -#define PROC_CSTATE_DIR "/proc/acpi/processor" -#define MAX_C_STATES 8 -#define FREQ_ACPI 3.579545 -#endif - - -#if !__FreeBSD__ && !sun - -/* - *----------------------------------------------------------------------------- - * - * Util_BumpNoFds -- - * - * Bump the number of file descriptor this process can open to 2048. On - * failure sets *cur to the number of fds we can currently open, and sets - * *wanted to what we want. - * - * Results: - * 0 on success, errno from the failing call to setrlimit(2) otherwise. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -int -Util_BumpNoFds(uint32 *cur, // OUT - uint32 *wanted) // OUT -{ - struct rlimit lim; - int err; - - /* - * Check for minimum file descriptor limit. The number is - * somewhat arbitrary. Trying to do multiple snapshots of a split - * disk can rapidly consume descriptors however, so we ought to - * have a large number. This is only pushing back the problem of - * course. Ideally we'd have a fully scalable solution. - */ - -#if __APPLE__ - static const rlim_t fdsDesired = 8192; -#else - static const rlim_t fdsDesired = 2048; -#endif - - err = getrlimit(RLIMIT_NOFILE, &lim); - ASSERT_NOT_IMPLEMENTED(err >= 0); - - if (cur) { - *cur = lim.rlim_cur; - } - if (wanted) { - *wanted = fdsDesired; - } - - if (lim.rlim_cur != RLIM_INFINITY && lim.rlim_cur < fdsDesired) { - Bool needSu; - - /* - * First attempt to raise limit ourselves. - * If that fails, complain and make user do it. - */ - - rlim_t curFdLimit = lim.rlim_cur; - rlim_t maxFdLimit = lim.rlim_max; - - lim.rlim_cur = fdsDesired; - - /* - * rlim_max may need to be increased as well. - */ - - needSu = lim.rlim_max != RLIM_INFINITY && lim.rlim_max < fdsDesired; - - if (needSu) { - lim.rlim_max = fdsDesired; - } else { - err = setrlimit(RLIMIT_NOFILE, &lim) < 0 ? errno : 0; - } - - /* - * Set euid to root for the FD limit increase. Note we don't need root - * unless rlim_max is being increased. Revert to non-root immediately - * after. - */ - - if (err == EPERM || needSu) { - uid_t uid = Id_BeginSuperUser(); - - err = setrlimit(RLIMIT_NOFILE, &lim) < 0 ? errno : 0; - Id_EndSuperUser(uid); - } - - /* - * If everything else failed, simply try using rlim_max. That might be - * enough.. - */ - - if (err != 0) { - lim.rlim_cur = maxFdLimit; - lim.rlim_max = maxFdLimit; - err = setrlimit(RLIMIT_NOFILE, &lim) < 0 ? errno : 0; - ASSERT_NOT_TESTED(err == 0); - } - - if (err != 0) { - Log("UTIL: Failed to set number of fds at %u, was %u: %s (%d)\n", - (uint32)fdsDesired, (uint32)curFdLimit, Err_Errno2String(err), - err); - } - } - - return err; -} - - -/* - *----------------------------------------------------------------------------- - * - * UtilGetUserName -- - * - * Retrieve the name associated with a user ID. Thread-safe - * version. --hpreg - * - * Results: - * The allocated name on success - * NULL on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static char * -UtilGetUserName(uid_t uid) // IN -{ - long memPoolSize; - char *memPool; - struct passwd pw; - struct passwd *pw_p; - char *userName; - -#if __APPLE__ - memPoolSize = _PASSWORD_LEN; -#else - memPoolSize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (memPoolSize <= 0) { - Warning("%s: sysconf(_SC_GETPW_R_SIZE_MAX) failed.\n", __FUNCTION__); - - return NULL; - } -#endif - - memPool = malloc(memPoolSize); - if (memPool == NULL) { - Warning("%s: Not enough memory.\n", __FUNCTION__); - - return NULL; - } - - if (Posix_Getpwuid_r(uid, &pw, memPool, memPoolSize, &pw_p) != 0) { - free(memPool); - Warning("%s: Unable to retrieve the username associated with " - "user ID %u.\n", __FUNCTION__, uid); - - return NULL; - } - - userName = strdup(pw_p->pw_name); - free(memPool); - if (userName == NULL) { - Warning("%s: Not enough memory.\n", __FUNCTION__); - - return NULL; - } - - return userName; -} - - -/* - *---------------------------------------------------------------------- - * - * Util_MakeSafeTemp -- - * - * Exactly the same as File_MakeTemp except uses a safe directory - * as the default temporary directory. - * - * This code is duplicated in identical form between utilPosix.c - * and utilWin32.c, but can't go in util.c because it depends on - * Util_GetSafeTmpDir whose Win32 implementation implies extra - * dependencies that some people who link just to util.c can't - * stomach. - * - * Results: - * Open file descriptor or -1 - * - * Side effects: - * Creates a file if successful. - *---------------------------------------------------------------------- - */ - -int -Util_MakeSafeTemp(ConstUnicode tag, // IN (OPT): - Unicode *presult) // OUT: -{ - int fd = -1; - Unicode dir = NULL; - Unicode fileName = NULL; - - *presult = NULL; - - if (tag && File_IsFullPath(tag)) { - File_GetPathName(tag, &dir, &fileName); - } else { - dir = Util_GetSafeTmpDir(TRUE); - fileName = Unicode_Duplicate(tag ? tag : "vmware"); - } - - fd = File_MakeTempEx(dir, fileName, presult); - - Unicode_Free(dir); - Unicode_Free(fileName); - - return fd; -} - - -/* - *----------------------------------------------------------------------------- - * - * UtilAcceptableSafeTmpDir -- - * - * Determines if the specified path is acceptable as the safe - * temp directory. The directory must either be creatable - * with the appropriate permissions and userId or it must - * already exist with those settings. - * - * Results: - * TRUE if path is acceptible, FALSE otherwise - * - * Side effects: - * Directory may be created - * - *----------------------------------------------------------------------------- - */ - -static Bool -UtilAcceptableSafeTmpDir(const char *dirname, // IN - int userId) // IN -{ - Bool result; - static const mode_t mode = 0700; - - result = (Posix_Mkdir(dirname, mode) == 0); - if (!result) { - int error = errno; - - if (EEXIST == error) { - struct stat st; - - /* - * The name already exists. Check that it is what we want: a - * directory owned by the current effective user with - * permissions 'mode'. It is crucial to use lstat() instead of - * stat() here, because we do not want the name to be a symlink - * (created by another user) pointing to a directory owned by - * the current effective user with permissions 'mode'. - */ - - if (0 == Posix_Lstat(dirname, &st)) { - /* - * Our directory inherited S_ISGID if its parent had it. So it - * is important to ignore that bit, and it is safe to do so - * because that bit does not affect the owner's - * permissions. - */ - - if (S_ISDIR(st.st_mode) && - (st.st_uid == userId) && - ((st.st_mode & 05777) == mode)) { - result = TRUE; - } - } - } - } - - return result; -} - - -/* - *----------------------------------------------------------------------------- - * - * UtilFindExistingSafeTmpDir -- - * - * Searches the directory baseTmpDir to see if any subdirectories - * are suitable to use as the safe temp directory. The safe temp - * directory must have the correct permissions and userId. - * - * Results: - * Path to discovered safe temp directory (must be freed). - * NULL returned if no suitable directory is found. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static Unicode -UtilFindExistingSafeTmpDir(uid_t userId, // IN - const char * userName, // IN - const char * baseTmpDir) // IN -{ - int i; - int numFiles; - Unicode pattern; - Unicode tmpDir = NULL; - Unicode *fileList = NULL; - - /* - * We always use the pattern PRODUCT-USER-xxxx when creating - * alternative safe temp directories, so check for ones with - * those names and the appropriate permissions. - */ - - pattern = Unicode_Format("%s-%s-", PRODUCT_GENERIC_NAME_LOWER, userName); - if (pattern == NULL) { - return NULL; - } - - numFiles = File_ListDirectory(baseTmpDir, &fileList); - - if (numFiles == -1) { - Unicode_Free(pattern); - return NULL; - } - - for (i = 0; i < numFiles; i++) { - if (Unicode_StartsWith(fileList[i], pattern)) { - Unicode path = Unicode_Join(baseTmpDir, DIRSEPS, fileList[i], - NULL); - - if (File_IsDirectory(path) && - UtilAcceptableSafeTmpDir(path, userId)) { - tmpDir = path; - break; - } - - Unicode_Free(path); - } - } - - Unicode_FreeList(fileList, numFiles); - Unicode_Free(pattern); - - return tmpDir; -} - -/* - *----------------------------------------------------------------------------- - * - * UtilCreateSafeTmpDir -- - * - * Creates a new directory within baseTmpDir with the correct - * permissions and userId to ensure it is safe from symlink attacks. - * - * Results: - * Path to created safe temp directory (must be freed). - * NULL returned if no suitable directory could be created. - * - * Side effects: - * Directory may be created. - * - *----------------------------------------------------------------------------- - */ - -static char * -UtilCreateSafeTmpDir(uid_t userId, // IN - const char * userName, // IN - const char * baseTmpDir) // IN -{ - static const int MAX_DIR_ITERS = 250; - char *tmpDir = NULL; - int curDirIter; - - curDirIter = 0; - while (TRUE) { - unsigned int suffix; - - /* - * We use a crypographically strong random number which is - * overkill for this purpose but makes it slightly more likely - * that we will create an unused name than if we had simply tried - * suffixes in numeric order. - */ - - if (!Random_Crypto(sizeof(suffix), &suffix)) { - Warning("%s: Call to Random_Crypto failed.\n", __FUNCTION__); - break; - } - - tmpDir = Str_Asprintf(NULL, "%s"DIRSEPS"%s-%s-%u", baseTmpDir, - PRODUCT_GENERIC_NAME_LOWER, userName, suffix); - - if (!tmpDir) { - Warning("%s: Out of memory error.\n", __FUNCTION__); - break; - } - - if (UtilAcceptableSafeTmpDir(tmpDir, userId)) { - break; - } - - if (++curDirIter > MAX_DIR_ITERS) { - Warning("%s: Failed to create a safe temporary " - "directory, path \"%s\". The maximum number of attempts was " - "exceeded.\n", __FUNCTION__, tmpDir); - free(tmpDir); - tmpDir = NULL; - break; - } - - free(tmpDir); - tmpDir = NULL; - } - - return tmpDir; -} - -/* - *----------------------------------------------------------------------------- - * - * Util_GetSafeTmpDir -- - * - * Return a safe temporary directory (i.e. a temporary directory - * which is not prone to symlink attacks, because it is only - * writable by the current effective user). Guaranteed to return - * the same directory every time it is called during the lifetime - * of the current process (unless that directory is deleted while - * the process is running). - * - * Results: - * The allocated directory path on success. - * NULL on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -char * -Util_GetSafeTmpDir(Bool useConf) // IN -{ - static Atomic_Ptr lckStorage; - static char *safeDir; - char *tmpDir = NULL; - char *baseTmpDir = NULL; - char *userName = NULL; - uid_t userId; - MXUserExclLock *lck; - - userId = geteuid(); - - /* Get and take lock for our safe dir. */ - lck = MXUser_CreateSingletonExclLock(&lckStorage, __FUNCTION__, - RANK_UNRANKED); - ASSERT_NOT_IMPLEMENTED(lck != NULL); - - MXUser_AcquireExclLock(lck); - - /* - * Check if we've created a temporary dir already and if it is - * still usable. - */ - if (safeDir && UtilAcceptableSafeTmpDir(safeDir, userId)) { - tmpDir = Util_SafeStrdup(safeDir); - goto exit; - } - - /* We don't have a useable temporary dir, create one. */ - baseTmpDir = File_GetTmpDir(useConf); - - if (!baseTmpDir) { - Warning("%s: File_GetTmpDir failed.\n", __FUNCTION__); - goto exit; - } - - userName = UtilGetUserName(userId); - - if (!userName) { - Warning("%s: UtilGetUserName failed, using numeric ID " - "as username instead.\n", __FUNCTION__); - - /* Fallback on just using the userId as the username. */ - userName = Str_Asprintf(NULL, "uid-%d", userId); - - if (!userName) { - Warning("%s: Str_Asprintf error.\n", __FUNCTION__); - goto exit; - } - } - - tmpDir = Str_Asprintf(NULL, "%s"DIRSEPS"%s-%s", baseTmpDir, - PRODUCT_GENERIC_NAME_LOWER, userName); - - if (!tmpDir) { - Warning("%s: Out of memory error.\n", __FUNCTION__); - goto exit; - } - - if (!UtilAcceptableSafeTmpDir(tmpDir, userId)) { - /* - * We didn't get our first choice for the safe temp directory. - * Search through the unsafe tmp directory to see if there is - * an acceptable one to use. - */ - - free(tmpDir); - - tmpDir = UtilFindExistingSafeTmpDir(userId, userName, baseTmpDir); - - if (!tmpDir) { - /* - * We didn't find any usable directories, so try to create one - * now. - */ - - tmpDir = UtilCreateSafeTmpDir(userId, userName, baseTmpDir); - } - } - - if (tmpDir) { - /* - * We have successfully created a temporary directory, remember it for - * future calls. - */ - - free(safeDir); - safeDir = Util_SafeStrdup(tmpDir); - } - - exit: - MXUser_ReleaseExclLock(lck); - free(baseTmpDir); - free(userName); - - return tmpDir; -} - -#endif // __linux__ - - -#if defined(__linux__) || defined(__FreeBSD__) || defined(sun) -/* - *---------------------------------------------------------------------------- - * - * Util_GetProcessName -- - * - * Tries to locate the process name of the specified process id. The - * process' name is placed in bufOut. - * - * Results: - * TRUE on success, FALSE on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -Util_GetProcessName(pid_t pid, // IN : process id - char *bufOut, // OUT: output buffer - size_t bufOutSize) // IN : buffer size -{ - int fd; - int nread; - char *psname; - size_t psnameLen; - char fileName[MAXPATHLEN]; -#ifdef sun - char buf[sizeof (psinfo_t)]; -#else - char buf[PSINFOSZ]; - char psinfo[PSINFOSZ]; -#endif - - ASSERT(bufOut); - - /* - * Open up /proc//status on Linux/FreeBSD, and /proc//psinfo on - * Solaris. - */ - - Str_Sprintf(fileName, sizeof fileName, "/proc/%"FMTPID"/" PROCFILE, pid); - - fd = Posix_Open(fileName, O_RDONLY); - if (fd < 0) { - Log("%s: Error: cannot open %s\n", __FUNCTION__, fileName); - - return FALSE; - } - - nread = read(fd, buf, sizeof buf); -#ifdef sun - if (nread != sizeof buf) { -#else - if (nread < 0) { -#endif - Log("%s: Error: could not read %s\n", __FUNCTION__, fileName); - close(fd); - - return FALSE; - } - - close(fd); - -#ifdef sun - psname = ((psinfo_t *)buf)->pr_fname; -#else /* Linux & FreeBSD */ - ASSERT(nread <= sizeof buf); - buf[nread == sizeof buf ? nread - 1 : nread] = '\0'; - - /* - * Parse the plain text formatting of the status file. Note that PSINFOFMT - * contains a format modifier to ensure psinfo is not overrun. - */ - - if (sscanf(buf, PRE PSINFOFMT POST, psinfo) != 1) { - Log("%s: Error, could not parse contents of %s\n", __FUNCTION__, - fileName); - - return FALSE; - } - - Escape_UnescapeCString(psinfo); - - psname = psinfo; -#endif /* sun */ - - psnameLen = strlen(psname); - if (psnameLen + 1 > bufOutSize) { - Log("%s: Error, process name (%"FMTSZ"u bytes) is larger " - "than output buffer\n", __FUNCTION__, psnameLen); - - return FALSE; - } - - memcpy(bufOut, psname, psnameLen + 1); - - return TRUE; -} -#endif - -#if defined(VMX86_STATS) -#if defined(__linux__) && !defined(VMX86_SERVER) -/* - *---------------------------------------------------------------------------- - * - * UtilAllocCStArrays -- - * - * (Re-)Allocate data arrays for UtilReadSysCStRes and UtilReadProcCStRes. - * - * Results: - * TRUE if successful. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static Bool -UtilAllocCStArrays(uint32 ncpus, // IN - uint32 nstates, // IN - uint64 **transitns, // OUT - uint64 **residency, // OUT - uint64 **transTime, // OUT - uint64 **residTime) // OUT -{ - free(*transitns); - free(*residency); - free(*transTime); - free(*residTime); - - *transitns = calloc(nstates * ncpus, sizeof **transitns); - *residency = calloc(nstates * ncpus, sizeof **residency); - *transTime = calloc(ncpus, sizeof **transTime); - *residTime = calloc(ncpus, sizeof **residTime); - - if (!*transitns || !*residency || !*transTime || !*residTime) { - free(*transitns); - free(*residency); - free(*transTime); - free(*residTime); - Warning("%s: Cannot allocate memory for C-state queries\n", - __FUNCTION__); - - return FALSE; - } - - return TRUE; -} - - -/* - *---------------------------------------------------------------------------- - * - * UtilReadSysCStRes -- - * UtilReadProcCStRes -- - * - * Read the C-state residency statistics under /sys and /proc - * respectively. UtilReadSysCStRes should take precedence over - * UtilReadProcCStRes as /proc/acpi is getting replaced by sysfs - * in newer kernels. See Util_QueryCStResidency for description of - * parameters. - * - * Results: - * TRUE if successful. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static Bool -UtilReadSysCStRes(DIR *dir, // IN - uint32 *numCpus, // IN/OUT - uint32 *numCStates, // IN/OUT - uint64 **transitns, // OUT - uint64 **residency, // OUT - uint64 **transTime, // OUT - uint64 **residTime) // OUT -{ - struct dirent *cpuEntry; - DIR *cpuDir; - struct dirent *cstateEntry; - char pathname[PATH_MAX + 1]; - uint32 cpu = 0; - uint32 cl = 0; - - /* Determine the number of cpus and c-states. */ - while ((cpuEntry = readdir(dir))) { - if (Str_Strncasecmp(cpuEntry->d_name, "cpu", 3) == 0 && - isdigit(cpuEntry->d_name[3])) { - cpu++; - if (cl != 0) { /* already found the number of c states */ - continue; - } - if (Str_Snprintf(pathname, sizeof pathname, - SYS_CSTATE_DIR"/%s/cpuidle", - cpuEntry->d_name) <= 0) { - LOG(0, ("%s: Str_Snprintf failed\n", __FUNCTION__)); - - return FALSE; - } - cpuDir = Posix_OpenDir(pathname); - if (cpuDir != NULL) { - uint32 cnum; - - while ((cstateEntry = readdir(cpuDir))) { - if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) == 0 && - sscanf(cstateEntry->d_name + 5, "%u", &cnum) == 1 && - cnum > cl) { - cl = cnum; /* state0 will be ignored */ - } - } - closedir(cpuDir); - } - } - } - if (cpu == 0 || cl == 0) { - return FALSE; - } - - if (*numCpus != cpu || *numCStates != cl) { - if (!UtilAllocCStArrays(cpu, cl, transitns, residency, transTime, - residTime)) { - return FALSE; - } - *numCpus = cpu; - *numCStates = cl; - } - - rewinddir(dir); - cpu = 0; - while ((cpuEntry = readdir(dir))) { - int pathlen; - VmTimeType timeUS; - - if (Str_Strncasecmp(cpuEntry->d_name, "cpu", 3) != 0 || - !isdigit(cpuEntry->d_name[3])) { - continue; - } - pathlen = Str_Snprintf(pathname, sizeof pathname, - SYS_CSTATE_DIR"/%s/cpuidle", cpuEntry->d_name); - if (pathlen <= 0) { - LOG(0, ("%s: Str_Snprintf for '%s/cpuidle' failed\n", __FUNCTION__, - cpuEntry->d_name)); - - return FALSE; - } - cpuDir = Posix_OpenDir(pathname); - if (cpuDir == NULL) { - LOG(0, ("%s: Failed to open directory %s\n", __FUNCTION__, pathname)); - continue; - } - - /* - * Under the "cpuidle" directory, there is one "stateX" directory for - * each C-state. We ignore "state0", i.e. C0, which is the running state. - * Under each "stateX" directory, there is a "usage" file which contains - * the number of entries into that state, and a "time" file which - * contains the total residency in that state. - */ - - while ((cstateEntry = readdir(cpuDir))) { - FILE *statsFile; - int result; - uint32 index; - - if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) != 0) { - continue; - } - if (sscanf(cstateEntry->d_name + 5, "%u", &cl) != 1 || cl == 0) { - continue; - } - cl--; /* ignoring state0 -- cl == 0 -> state1 */ - index = *numCStates * cpu + cl; - - if (Str_Snprintf(pathname + pathlen, sizeof pathname - pathlen, - "/%s/usage", cstateEntry->d_name) <= 0) { - LOG(0, ("%s: Str_Snprintf for 'usage' failed\n", __FUNCTION__)); - closedir(cpuDir); - - return FALSE; - } - statsFile = Posix_Fopen(pathname, "r"); - if (statsFile == NULL) { - continue; - } - result = fscanf(statsFile, "%"FMT64"u", &(*transitns)[index]); - fclose(statsFile); - if (result <= 0) { - continue; - } - - if (Str_Snprintf(pathname + pathlen, sizeof pathname - pathlen, - "/%s/time", cstateEntry->d_name) <= 0) { - LOG(0, ("%s: Str_Snprintf for 'time' failed\n", __FUNCTION__)); - closedir(cpuDir); - - return FALSE; - } - statsFile = Posix_Fopen(pathname, "r"); - if (statsFile == NULL) { - continue; - } - result = fscanf(statsFile, "%"FMT64"u", &(*residency)[index]); - fclose(statsFile); - if (result <= 0) { - continue; - } - } - closedir(cpuDir); - - timeUS = Hostinfo_SystemTimerUS(); - if (timeUS <= 0) { - LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__)); - - return FALSE; - } - (*transTime)[cpu] = timeUS; - (*residTime)[cpu] = timeUS; - cpu++; - } - - return cpu > 0; -} - - -static Bool -UtilReadProcCStRes(DIR *dir, // IN - uint32 *numCpus, // IN/OUT - uint32 *numCStates, // IN/OUT - uint64 **transitns, // OUT - uint64 **residency, // OUT - uint64 **transTime, // OUT - uint64 **residTime) // OUT -{ - struct dirent *cpuEntry; - uint32 cpu = 0; - - /* Determine the number of cpus. */ - while ((cpuEntry = readdir(dir))) { - if (cpuEntry->d_name[0] != '.') { - cpu++; - } - } - if (cpu == 0) { - return FALSE; - } - - if (*numCpus != cpu) { - /* - * We do not know the number of C-states supported until we read the - * file, so we allocate for MAX_C_STATES and determine *numCStates later. - */ - - if (!UtilAllocCStArrays(cpu, MAX_C_STATES, transitns, residency, - transTime, residTime)) { - return FALSE; - } - *numCpus = cpu; - *numCStates = 0; - } - - rewinddir(dir); - cpu = 0; - while ((cpuEntry = readdir(dir))) { - char pathname[PATH_MAX + 1]; - char *line; - size_t lineSize; - FILE *powerFile; - uint32 cl; - VmTimeType timeUS; - - if (cpuEntry->d_name[0] == '.') { - continue; - } - if (Str_Snprintf(pathname, sizeof pathname, PROC_CSTATE_DIR"/%s/power", - cpuEntry->d_name) <= 0) { - LOG(0, ("%s: Str_Snprintf for '%s/power' failed\n", __FUNCTION__, - cpuEntry->d_name)); - - return FALSE; - } - powerFile = Posix_Fopen(pathname, "r"); - if (powerFile == NULL) { - continue; - } - - cl = 0; - while (StdIO_ReadNextLine(powerFile, &line, 0, - &lineSize) == StdIO_Success) { - char *ptr; - uint32 index = *numCStates * cpu + cl; - - if ((ptr = Str_Strnstr(line, "usage[", lineSize))) { - sscanf(ptr + 6, "%"FMT64"u]", &(*transitns)[index]); - if ((ptr = Str_Strnstr(line, "duration[", lineSize))) { - sscanf(ptr + 9, "%"FMT64"u]", &(*residency)[index]); - cl++; - } - } - free(line); - } - fclose(powerFile); - - timeUS = Hostinfo_SystemTimerUS(); - if (timeUS <= 0) { - LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__)); - - return FALSE; - } - (*transTime)[cpu] = timeUS; - (*residTime)[cpu] = (uint64)((double)timeUS * FREQ_ACPI); - if (*numCStates == 0) { - *numCStates = cl; - } - cpu++; - } - - return cpu > 0 && *numCStates > 0; -} - - -/* - *---------------------------------------------------------------------------- - * - * Util_QueryCStResidency -- - * - * Query CPU's C-state residency statistics exposed by the host OS. - * On Linux, this is done via either the sysfs or /proc/acpi interface. - * - * The parameters transitns, residency, transTime and residTime are - * pointers to uint64 arrays, whose dimensions are specified by - * *numCpus and/or *numCStates: - * transitns -- number of trasitions into each c-state for each CPU - * residency -- time in each c-state for each CPU (in some opaque unit) - * transTime -- timestamp (microseconds) for transitns data, per CPU - * residTime -- timestamp for residency data, per CPU (in same unit as - * residency) - * - * If the dimensions specified are too small, the arrays are freed - * and new memory allocated. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -Util_QueryCStResidency(uint32 *numCpus, // IN/OUT - uint32 *numCStates, // IN/OUT - uint64 **transitns, // OUT - uint64 **residency, // OUT - uint64 **transTime, // OUT - uint64 **residTime) // OUT -{ - DIR *dir; - Bool ret = FALSE; - - dir = Posix_OpenDir(SYS_CSTATE_DIR); - if (dir) { - ret = UtilReadSysCStRes(dir, numCpus, numCStates, transitns, residency, - transTime, residTime); - closedir(dir); - } - - if (!ret) { - dir = Posix_OpenDir(PROC_CSTATE_DIR); - if (dir) { - ret = UtilReadProcCStRes(dir, numCpus, numCStates, transitns, - residency, transTime, residTime); - closedir(dir); - } - } - - return ret; -} - -#else // #if defined(__linux__) && !defined(VMX86_SERVER) - -Bool -Util_QueryCStResidency(uint32 *numCpus, // IN/OUT - uint32 *numCStates, // IN/OUT - uint64 **transitns, // OUT - uint64 **residency, // OUT - uint64 **transTime, // OUT - uint64 **residTime) // OUT -{ - return FALSE; -} -#endif -#endif // #if defined(VMX86_STATS)