1
/*********************************************************
2
* Copyright (C) 1998 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
*********************************************************/
22
* Interface to host-specific information functions for Posix hosts
24
* I created this file for this only reason: the functions it contains should
25
* be callable by _any_ VMware userland program --hpreg
34
#include <sys/utsname.h>
40
#include <sys/types.h>
44
#include <sys/timeb.h>
46
#include <sys/resource.h>
47
#if defined(__APPLE__)
48
#define SYS_NMLN _SYS_NAMELEN
50
#include <CoreServices/CoreServices.h>
51
#include <mach-o/dyld.h>
52
#include <mach/host_info.h>
53
#include <mach/mach_host.h>
54
#include <mach/mach_init.h>
55
#include <mach/mach.h>
56
#include <mach/mach_time.h>
57
#include <sys/sysctl.h>
58
#elif defined(__FreeBSD__)
59
#include <sys/sysctl.h>
60
#if !defined(RLIMIT_AS)
61
# if defined(RLIMIT_VMEM)
62
# define RLIMIT_AS RLIMIT_VMEM
64
# define RLIMIT_AS RLIMIT_RSS
68
#if !defined(USING_AUTOCONF) || defined(HAVE_SYS_VFS_H)
71
#if !defined(sun) && (!defined(USING_AUTOCONF) || (defined(HAVE_SYS_IO_H) && defined(HAVE_SYS_SYSINFO_H)))
73
#include <sys/sysinfo.h>
75
#define HAVE_SYSINFO 1
80
#if defined(__APPLE__) || defined(__FreeBSD__)
85
#define _PATH_DEVNULL "/dev/null"
91
#include "vm_version.h"
97
#include "backdoor_def.h"
101
#include "vm_atomic.h"
102
#include "x86cpuid.h"
103
#include "syncMutex.h"
107
#include "uwvmkAPI.h"
109
#include "vmkSyscall.h"
112
#define LGPFX "HOSTINFO:"
113
#define MAX_LINE_LEN 128
126
#if !defined(__APPLE__) && !defined(__FreeBSD__)
127
static char *HostinfoGetCpuInfo(int nCpu, char *name);
128
#if !defined(VMX86_SERVER)
129
static Bool HostinfoGetMemInfo(char *name, unsigned int *value);
130
#endif // ifndef VMX86_SERVER
131
#endif // ifndef __APPLE__
135
*-----------------------------------------------------------------------------
137
* HostinfoGetLoadAverage --
139
* Returns system average load.
142
* TRUE on success, FALSE otherwise.
147
*-----------------------------------------------------------------------------
151
HostinfoGetLoadAverage(float *avg0, // IN/OUT
152
float *avg1, // IN/OUT
153
float *avg2) // IN/OUT
155
/* getloadavg(3) was introduced with glibc 2.2 */
156
#if defined(GLIBC_VERSION_22) || defined(__APPLE__)
160
res = getloadavg(avg, 3);
167
*avg0 = (float) avg[0];
170
*avg1 = (float) avg[1];
173
*avg2 = (float) avg[2];
178
* Not implemented. This function is currently only used in the vmx, so
179
* getloadavg is always available to us. If the linux tools ever need this,
180
* we can go back to having a look at the output of /proc/loadavg, but let's
181
* no do that now as long as it's not necessary.
190
*-----------------------------------------------------------------------------
192
* Hostinfo_GetLoadAverage --
194
* Returns system average load * 100.
202
*-----------------------------------------------------------------------------
206
Hostinfo_GetLoadAverage(uint32 *avg) // IN/OUT
210
if (!HostinfoGetLoadAverage(&avg0, NULL, NULL)) {
213
*avg = (uint32) 100 * avg0;
219
*-----------------------------------------------------------------------------
221
* Hostinfo_LogLoadAverage --
223
* Logs system average load.
231
*-----------------------------------------------------------------------------
235
Hostinfo_LogLoadAverage(void)
237
float avg0, avg1, avg2;
239
if (!HostinfoGetLoadAverage(&avg0, &avg1, &avg2)) {
242
Log("LOADAVG: %.2f %.2f %.2f\n", avg0, avg1, avg2);
245
#if defined(__APPLE__)
247
*-----------------------------------------------------------------------------
249
* HostinfoMacAbsTimeNS --
251
* Return the Mac OS absolute time.
254
* The absolute time in nanoseconds is returned. This time is documented
255
* to NEVER go backwards.
260
*-----------------------------------------------------------------------------
263
static inline VmTimeType
264
HostinfoMacAbsTimeNS(void)
267
mach_timebase_info_data_t *ptr;
268
static Atomic_Ptr atomic; /* Implicitly initialized to NULL. --mbellon */
270
/* Insure that the time base values are correct. */
271
ptr = (mach_timebase_info_data_t *) Atomic_ReadPtr(&atomic);
276
p = Util_SafeMalloc(sizeof(mach_timebase_info_data_t));
278
mach_timebase_info((mach_timebase_info_data_t *) p);
280
if (Atomic_ReadIfEqualWritePtr(&atomic, NULL, p)) {
284
ptr = (mach_timebase_info_data_t *) Atomic_ReadPtr(&atomic);
287
raw = mach_absolute_time();
289
if ((ptr->numer == 1) && (ptr->denom == 1)) {
290
/* The scaling values are unity, save some time/arithmetic */
293
/* The scaling values are not unity. Prevent overflow when scaling */
294
return ((double) raw) * (((double) ptr->numer) / ((double) ptr->denom));
301
*-----------------------------------------------------------------------------
303
* HostinfoRawSystemTimerUS --
305
* Obtain the raw system timer value.
308
* Relative time in microseconds or zero if a failure.
313
*-----------------------------------------------------------------------------
317
Hostinfo_RawSystemTimerUS(void)
319
#if defined(__APPLE__)
320
return HostinfoMacAbsTimeNS() / 1000ULL;
322
#if defined(VMX86_SERVER)
323
if (HostType_OSIsPureVMK()) {
325
VMK_ReturnStatus status;
327
status = VMKernel_GetUptimeUS(&uptime);
328
if (status != VMK_OK) {
329
Log("%s: failure!\n", __FUNCTION__);
330
return 0; // A timer read failure - this is really bad!
335
#endif /* ifdef VMX86_SERVER */
338
/* Read the time from the operating system */
339
if (gettimeofday(&tval, NULL) != 0) {
340
Log("%s: failure!\n", __FUNCTION__);
341
return 0; // A timer read failure - this is really bad!
343
/* Convert into microseconds */
344
return (((VmTimeType)tval.tv_sec) * 1000000 + tval.tv_usec);
345
#if defined(VMX86_SERVER)
347
#endif /* ifdef VMX86_SERVER */
348
#endif /* ifdef __APPLE__ */
353
*-----------------------------------------------------------------------------
355
* Hostinfo_SystemTimerUS --
357
* This is the routine to use when performing timing measurements. It
358
* is valid (finish-time - start-time) only within a single process.
359
* Don't send a time obtained this way to another process and expect
360
* a relative time measurement to be correct.
362
* This timer is documented to never go backwards.
365
* Relative time in microseconds or zero if a failure.
367
* Please note that the actual resolution of this "clock" is undefined -
368
* it varies between OSen and OS versions.
373
*-----------------------------------------------------------------------------
377
Hostinfo_SystemTimerUS(void)
383
static Atomic_Ptr lckStorage;
384
static VmTimeType lastTimeBase;
385
static VmTimeType lastTimeRead;
386
static VmTimeType lastTimeReset;
388
/* Get and take lock. */
389
lck = SyncMutex_CreateSingleton(&lckStorage);
392
curTime = Hostinfo_RawSystemTimerUS();
400
* Don't let time be negative or go backward. We do this by
401
* tracking a base and moving foward from there.
404
newTime = lastTimeBase + (curTime - lastTimeReset);
406
if (newTime < lastTimeRead) {
407
lastTimeReset = curTime;
408
lastTimeBase = lastTimeRead + 1;
409
newTime = lastTimeBase + (curTime - lastTimeReset);
412
lastTimeRead = newTime;
416
SyncMutex_Unlock(lck);
422
*-----------------------------------------------------------------------------
424
* Hostinfo_SystemUpTime --
426
* Return system uptime in microseconds.
428
* Please note that the actual resolution of this "clock" is undefined -
429
* it varies between OSen and OS versions. Use Hostinfo_SystemTimerUS
433
* System uptime in microseconds or zero in case of a failure.
438
*-----------------------------------------------------------------------------
442
Hostinfo_SystemUpTime(void)
444
#if defined(__APPLE__)
445
return HostinfoMacAbsTimeNS() / 1000ULL;
446
#elif defined(VMX86_SERVER)
448
VMK_ReturnStatus status;
450
if (VmkSyscall_Init(FALSE, NULL, 0)) {
451
status = CosVmnix_GetUptimeUS(&uptime);
452
if (status == VMK_OK) {
458
#elif defined(__linux__)
464
static Atomic_Int fdStorage = { -1 };
465
static Atomic_uint32 logFailedPread = { 1 };
467
fd = Atomic_ReadInt(&fdStorage);
469
/* Do we need to open the file the first time through? */
470
if (UNLIKELY(fd == -1)) {
471
fd = open("/proc/uptime", O_RDONLY);
474
Warning(LGPFX" Failed to open /proc/uptime: %s\n", Msg_ErrString());
478
/* Try to swap ours in. If we lose the race, close our fd */
479
if (Atomic_ReadIfEqualWriteInt(&fdStorage, -1, fd) != -1) {
483
/* Get the winning fd - either ours or theirs, doesn't matter anymore */
484
fd = Atomic_ReadInt(&fdStorage);
489
res = pread(fd, buf, sizeof buf - 1, 0);
492
* In case some kernel broke pread (like 2.6.28-rc1), have a fall-back
493
* instead of spewing the log. This should be rare. Using a lock
494
* around lseek and read does not work here as it will deadlock with
495
* allocTrack/fileTrack enabled.
498
if (Atomic_ReadIfEqualWrite(&logFailedPread, 1, 0) == 1) {
499
Warning(LGPFX" Failed to pread /proc/uptime: %s\n", Msg_ErrString());
501
fd = open("/proc/uptime", O_RDONLY);
503
Warning(LGPFX" Failed to retry open /proc/uptime: %s\n",
507
res = read(fd, buf, sizeof buf - 1);
510
Warning(LGPFX" Failed to read /proc/uptime: %s\n", Msg_ErrString());
514
ASSERT(res < sizeof buf);
517
if (sscanf(buf, "%lf", &uptime) != 1) {
518
Warning(LGPFX" Failed to parse /proc/uptime\n");
522
return uptime * 1000 * 1000;
530
*-----------------------------------------------------------------------------
532
* Hostinfo_NameGet --
534
* Return the fully qualified host name of the host.
535
* Thread-safe. --hpreg
538
* The (memorized) name on success
542
* A host name resolution can occur.
544
*-----------------------------------------------------------------------------
548
Hostinfo_NameGet(void)
552
static Atomic_Ptr state; /* Implicitly initialized to NULL. --hpreg */
554
result = Atomic_ReadPtr(&state);
556
if (UNLIKELY(result == NULL)) {
559
result = Hostinfo_HostName();
561
before = Atomic_ReadIfEqualWritePtr(&state, NULL, result);
564
Unicode_Free(result);
576
*----------------------------------------------------------------------
578
* HostinfoReadProc --
580
* Depending on what string is passed to it, this function parses the
581
* /proc/vmware/sched/ncpus node and returns the requested value.
584
* A postive value on success, -1 (0xFFFFFFFF) on failure.
589
*----------------------------------------------------------------------
593
HostinfoReadProc(const char *str)
595
/* XXX this should use sysinfo!! (bug 59849)
601
ASSERT(!strcmp("logical", str) || !strcmp("cores", str) || !strcmp("packages", str));
603
ASSERT(!HostType_OSIsVMK()); // Don't use /proc/vmware
605
f = Posix_Fopen("/proc/vmware/sched/ncpus", "r");
607
while (StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) {
608
if (strstr(line, str)) {
609
if (sscanf(line, "%d ", &count) == 1) {
628
*----------------------------------------------------------------------
630
* Hostinfo_HTDisabled --
632
* Figure out if hyperthreading is enabled
635
* TRUE if hyperthreading is disabled, FALSE otherwise
640
*----------------------------------------------------------------------
644
Hostinfo_HTDisabled(void)
646
static uint32 logical = 0, cores = 0;
648
if (HostType_OSIsVMK()) {
649
VMK_ReturnStatus status = VMKernel_HTEnabledCPU();
650
if (status != VMK_OK) {
657
if (logical == 0 && cores == 0) {
658
logical = HostinfoReadProc("logical");
659
cores = HostinfoReadProc("cores");
660
if (logical <= 0 || cores <= 0) {
665
return logical == cores;
667
#endif /*ifdef VMX86_SERVER*/
671
*-----------------------------------------------------------------------------
673
* Hostinfo_NumCPUs --
675
* Get the number of logical CPUs on the host. If the CPUs are
676
* hyperthread-capable, this number may be larger than the number of
677
* physical CPUs. For example, if the host has four hyperthreaded
678
* physical CPUs with 2 logical CPUs apiece, this function returns 8.
680
* This function returns the number of CPUs that the host presents to
681
* applications, which is what we want in the vast majority of cases. We
682
* would only ever care about the number of physical CPUs for licensing
686
* On success, the number of CPUs (> 0) the host tells us we have.
687
* On failure, 0xFFFFFFFF (-1).
692
*-----------------------------------------------------------------------------
696
Hostinfo_NumCPUs(void)
698
#if defined(__APPLE__)
700
size_t outSize = sizeof out;
703
* Quoting sys/sysctl.h:
705
* These are the support HW selectors for sysctlbyname. Parameters that are
706
* byte counts or frequencies are 64 bit numbers. All other parameters are
709
* hw.activecpu - The number of processors currently available for executing
710
* threads. Use this number to determine the number threads
711
* to create in SMP aware applications. This number can
712
* change when power management modes are changed.
715
* Apparently the only way to retrieve this info is by name, and I have
716
* verified the info changes when you dynamically switch a CPU
717
* offline/online. --hpreg
720
if (sysctlbyname("hw.activecpu", &out, &outSize, NULL, 0) == -1) {
725
#elif defined(__FreeBSD__)
727
size_t outSize = sizeof out;
729
#if __FreeBSD__version >= 500019
730
if (sysctlbyname("kern.smp.cpus", &out, &outSize, NULL, 0) == -1) {
734
if (sysctlbyname("machdep.smp_cpus", &out, &outSize, NULL, 0) == -1) {
735
if (errno == ENOENT) {
745
static int count = 0;
749
if (HostType_OSIsVMK()) {
750
VMK_ReturnStatus status = VMKernel_GetNumCPUsUsed(&count);
751
if (status != VMK_OK) {
756
count = HostinfoReadProc("logical");
762
#else /* ifdef VMX86_SERVER */
766
f = Posix_Fopen("/proc/cpuinfo", "r");
769
MSGID(hostlinux.opencpuinfo)
770
"Could not open /proc/cpuinfo.\n");
774
while (StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) {
775
if (strncmp(line, "processor", strlen("processor")) == 0) {
785
MSGID(hostlinux.readcpuinfo)
786
"Could not determine the number of processors from "
790
#endif /* ifdef VMX86_SERVER */
799
*-----------------------------------------------------------------------------
801
* Hostinfo_GetRatedCpuMhz --
803
* Get the rated CPU speed of a given processor.
804
* Return value is in MHz.
807
* TRUE on success, FALSE on failure
812
*-----------------------------------------------------------------------------
816
Hostinfo_GetRatedCpuMhz(int32 cpuNumber, // IN
819
#if defined(__APPLE__) || defined(__FreeBSD__)
821
# if defined(__APPLE__)
822
# define CPUMHZ_SYSCTL_NAME "hw.cpufrequency_max"
823
# elif __FreeBSD__version >= 50011
824
# define CPUMHZ_SYSCTL_NAME "hw.clockrate"
827
# if defined(CPUMHZ_SYSCTL_NAME)
829
size_t hzSize = sizeof hz;
831
// 'cpuNumber' is ignored: Intel Macs are always perfectly symetric.
833
if (sysctlbyname(CPUMHZ_SYSCTL_NAME, &hz, &hzSize, NULL, 0) == -1) {
844
char *readVal = HostinfoGetCpuInfo(cpuNumber, "cpu MHz");
846
if (readVal == NULL) {
850
if (sscanf(readVal, "%f", &fMhz) == 1) {
851
*mHz = (unsigned int)(fMhz + 0.5);
860
*-----------------------------------------------------------------------------
862
* Hostinfo_GetCpuDescription --
864
* Get the descriptive name associated with a given CPU.
867
* On success: Allocated, NUL-terminated string.
873
*-----------------------------------------------------------------------------
877
Hostinfo_GetCpuDescription(uint32 cpuNumber) // IN
879
#if defined(__APPLE__) || defined(__FreeBSD__)
880
# if defined(__APPLE__)
881
# define CPUDESC_SYSCTL_NAME "machdep.cpu.brand_string"
883
# define CPUDESC_SYSCTL_NAME "hw.model"
889
// 'cpuNumber' is ignored: Intel Macs are always perfectly symetric.
891
if (sysctlbyname(CPUDESC_SYSCTL_NAME, NULL, &descSize, NULL, 0)
896
desc = malloc(descSize);
901
if (sysctlbyname(CPUDESC_SYSCTL_NAME, desc, &descSize, NULL, 0)
910
if (HostType_OSIsVMK()) {
913
// VMKernel treats mName as an in/out parameter so terminate it.
915
if (VMKernel_GetCPUModelName(mName, cpuNumber, sizeof(mName)) == VMK_OK) {
916
mName[sizeof(mName) - 1] = '\0';
917
return strdup(mName);
922
return HostinfoGetCpuInfo(cpuNumber, "model name");
927
#if !defined(__APPLE__)
928
#if !defined(__FreeBSD__)
930
*----------------------------------------------------------------------
932
* HostinfoGetCpuInfo --
934
* Get some attribute from /proc/cpuinfo for a given CPU
937
* On success: Allocated, NUL-terminated attribute string.
943
*----------------------------------------------------------------------
947
HostinfoGetCpuInfo(int nCpu, // IN
955
f = Posix_Fopen("/proc/cpuinfo", "r");
957
Warning(LGPFX" HostinfoGetCpuInfo: Unable to open /proc/cpuinfo\n");
961
while (cpu <= nCpu &&
962
StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) {
966
if ((s = strstr(line, name)) &&
967
(s = strchr(s, ':'))) {
971
/* Skip leading and trailing while spaces */
972
for (; s < e && isspace(*s); s++);
973
for (; s < e && isspace(e[-1]); e--);
976
/* Free previous value */
979
ASSERT_MEM_ALLOC(value);
989
#endif /* __FreeBSD__ */
992
*----------------------------------------------------------------------
994
* HostinfoFindEntry --
996
* Search a buffer for a pair `STRING <blanks> DIGITS'
997
* and return the number DIGITS, or 0 when fail.
1000
* TRUE on success, FALSE on failure
1005
*----------------------------------------------------------------------
1009
HostinfoFindEntry(char *buffer, // IN: Buffer
1010
char *string, // IN: String sought
1011
unsigned int *value) // OUT: Value
1013
char *p = strstr(buffer, string);
1020
p += strlen(string);
1022
while (*p == ' ' || *p == '\t') {
1025
if (*p < '0' || *p > '9') {
1029
val = strtoul(p, NULL, 10);
1030
if (errno == ERANGE || errno == EINVAL) {
1040
*----------------------------------------------------------------------
1042
* HostinfoGetMemInfo --
1044
* Get some attribute from /proc/meminfo
1045
* Return value is in KB.
1048
* TRUE on success, FALSE on failure
1053
*----------------------------------------------------------------------
1057
HostinfoGetMemInfo(char *name, //IN
1058
unsigned int *value) //OUT
1063
int fd = Posix_Open("/proc/meminfo", O_RDONLY);
1066
Warning(LGPFX" HostinfoGetMemInfo: Unable to open /proc/meminfo\n");
1070
len = read(fd, buffer, sizeof buffer - 1);
1079
return HostinfoFindEntry(buffer, name, value);
1084
*-----------------------------------------------------------------------------
1086
* HostinfoSysinfo --
1088
* Retrieve system information on a Linux system.
1091
* TRUE on success: '*totalRam', '*freeRam', '*totalSwap' and '*freeSwap'
1092
* are set if not NULL
1098
* This seems to be a very expensive call: like 5ms on 1GHz P3 running
1099
* RH6.1 Linux 2.2.12-20. Yes, that's 5 milliseconds. So caller should
1100
* take care. -- edward
1102
*-----------------------------------------------------------------------------
1106
HostinfoSysinfo(uint64 *totalRam, // OUT: Total RAM in bytes
1107
uint64 *freeRam, // OUT: Free RAM in bytes
1108
uint64 *totalSwap, // OUT: Total swap in bytes
1109
uint64 *freeSwap) // OUT: Free swap in bytes
1112
// Found in linux/include/kernel.h for a 2.5.6 kernel --hpreg
1113
struct vmware_sysinfo {
1114
long uptime; /* Seconds since boot */
1115
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
1116
unsigned long totalram; /* Total usable main memory size */
1117
unsigned long freeram; /* Available memory size */
1118
unsigned long sharedram; /* Amount of shared memory */
1119
unsigned long bufferram; /* Memory used by buffers */
1120
unsigned long totalswap; /* Total swap space size */
1121
unsigned long freeswap; /* swap space still available */
1122
unsigned short procs; /* Number of current processes */
1123
unsigned short pad; /* explicit padding for m68k */
1124
unsigned long totalhigh; /* Total high memory size */
1125
unsigned long freehigh; /* Available high memory size */
1126
unsigned int mem_unit; /* Memory unit size in bytes */
1127
// Padding: libc5 uses this..
1128
char _f[20 - 2 * sizeof(long) - sizeof(int)];
1130
struct vmware_sysinfo si;
1132
if (sysinfo((struct sysinfo *)&si) < 0) {
1136
if (si.mem_unit == 0) {
1138
* Kernel versions < 2.3.23. Those kernels used a smaller sysinfo
1139
* structure, whose last meaningful field is 'procs' --hpreg
1145
*totalRam = (uint64)si.totalram * si.mem_unit;
1148
*freeRam = (uint64)si.freeram * si.mem_unit;
1151
*totalSwap = (uint64)si.totalswap * si.mem_unit;
1154
*freeSwap = (uint64)si.freeswap * si.mem_unit;
1158
#else // ifdef HAVE_SYSINFO
1160
#endif // ifdef HAVE_SYSINFO
1162
#endif // ifndef __APPLE__
1165
#if defined(__linux__) || defined(__FreeBSD__) || defined(sun)
1167
*-----------------------------------------------------------------------------
1169
* HostinfoGetLinuxMemoryInfoInPages --
1171
* Obtain the minimum memory to be maintained, total memory available, and
1172
* free memory available on the host (Linux or COS) in pages.
1175
* TRUE on success: '*minSize', '*maxSize' and '*currentSize' are set
1181
*-----------------------------------------------------------------------------
1185
HostinfoGetLinuxMemoryInfoInPages(unsigned int *minSize, // OUT
1186
unsigned int *maxSize, // OUT
1187
unsigned int *currentSize) // OUT
1191
unsigned int cached = 0;
1194
* Note that the free memory provided by linux does not include buffer and
1195
* cache memory. Linux tries to use the free memory to cache file. Most of
1196
* those memory can be freed immediately when free memory is low,
1197
* so for our purposes it should be counted as part of the free memory .
1198
* There is no good way to collect the useable free memory in 2.2 and 2.4
1201
* Here is our solution: The free memory we report includes cached memory.
1202
* Mmapped memory is reported as cached. The guest RAM memory, which is
1203
* mmaped to a ram file, therefore make up part of the cached memory. We
1204
* exclude the size of the guest RAM from the amount of free memory that we
1205
* report here. Since we don't know about the RAM size of other VMs, we
1206
* leave that to be done in serverd/MUI.
1209
if (HostinfoSysinfo(&total, &free, NULL, NULL) == FALSE) {
1214
* Convert to pages and round up total memory to the nearest multiple of 8
1215
* or 32 MB, since the "total" amount of memory reported by Linux is the
1216
* total physical memory - amount used by the kernel.
1218
if (total < (uint64)128 * 1024 * 1024) {
1219
total = ROUNDUP(total, (uint64)8 * 1024 * 1024);
1221
total = ROUNDUP(total, (uint64)32 * 1024 * 1024);
1224
*minSize = 128; // XXX - Figure out this value
1225
*maxSize = total / PAGE_SIZE;
1227
HostinfoGetMemInfo("Cached:", &cached);
1229
*currentSize = free / PAGE_SIZE + cached / (PAGE_SIZE / 1024);
1237
*-----------------------------------------------------------------------------
1239
* HostinfoGetSwapInfoInPages --
1241
* Obtain the total swap and free swap on the host (Linux or COS) in pages.
1244
* TRUE on success: '*totalSwap' and '*freeSwap' are set if not NULL
1250
*-----------------------------------------------------------------------------
1254
Hostinfo_GetSwapInfoInPages(unsigned int *totalSwap, // OUT
1255
unsigned int *freeSwap) // OUT
1260
if (HostinfoSysinfo(NULL, NULL, &total, &free) == FALSE) {
1264
if (totalSwap != NULL) {
1265
*totalSwap = total / PAGE_SIZE;
1268
if (freeSwap != NULL) {
1269
*freeSwap = free / PAGE_SIZE;
1278
*-----------------------------------------------------------------------------
1280
* Hostinfo_GetMemoryInfoInPages --
1282
* Obtain the minimum memory to be maintained, total memory available, and
1283
* free memory available on the host in pages.
1286
* TRUE on success: '*minSize', '*maxSize' and '*currentSize' are set
1292
*-----------------------------------------------------------------------------
1296
Hostinfo_GetMemoryInfoInPages(unsigned int *minSize, // OUT
1297
unsigned int *maxSize, // OUT
1298
unsigned int *currentSize) // OUT
1300
#if defined(__APPLE__)
1301
mach_msg_type_number_t count;
1302
vm_statistics_data_t stat;
1303
kern_return_t error;
1305
size_t memsizeSize = sizeof memsize;
1308
* Largely inspired by
1309
* darwinsource-10.4.5/top-15/libtop.c::libtop_p_vm_sample().
1312
count = HOST_VM_INFO_COUNT;
1313
error = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&stat,
1315
if (error != KERN_SUCCESS || count != HOST_VM_INFO_COUNT) {
1316
Warning("%s: Unable to retrieve host vm stats.\n", __FUNCTION__);
1320
// XXX Figure out this value.
1324
* XXX Hopefully this includes cached memory as well. We should check.
1325
* No. It returns only completely used pages.
1327
*currentSize = stat.free_count;
1330
* Adding up the stat values does not sum to 100% of physical memory.
1331
* The correct value is available from sysctl so we do that instead.
1333
if (sysctlbyname("hw.memsize", &memsize, &memsizeSize, NULL, 0) == -1) {
1334
Warning("%s: Unable to retrieve host vm hw.memsize.\n", __FUNCTION__);
1338
*maxSize = memsize / PAGE_SIZE;
1340
#elif defined(VMX86_SERVER)
1343
VMK_ReturnStatus status;
1345
if (VmkSyscall_Init(FALSE, NULL, 0)) {
1346
status = CosVmnix_GetMemSize(&total, &free);
1347
if (status == VMK_OK) {
1349
*maxSize = total / PAGE_SIZE;
1350
*currentSize = free / PAGE_SIZE;
1358
return HostinfoGetLinuxMemoryInfoInPages(minSize, maxSize, currentSize);
1365
*-----------------------------------------------------------------------------
1367
* Hostinfo_GetCOSMemoryInfoInPages --
1369
* Obtain the minimum memory to be maintained, total memory available, and
1370
* free memory available on the COS in pages.
1373
* TRUE on success: '*minSize', '*maxSize' and '*currentSize' are set
1379
*-----------------------------------------------------------------------------
1383
Hostinfo_GetCOSMemoryInfoInPages(unsigned int *minSize, // OUT
1384
unsigned int *maxSize, // OUT
1385
unsigned int *currentSize) // OUT
1387
if (HostType_OSIsPureVMK()) {
1390
return HostinfoGetLinuxMemoryInfoInPages(minSize, maxSize, currentSize);
1397
*----------------------------------------------------------------------
1399
* Hostinfo_ResetProcessState --
1401
* Clean up signal handlers and file descriptors before an exec().
1402
* Fds which need to be kept open can be passed as an array.
1410
*----------------------------------------------------------------------
1413
Hostinfo_ResetProcessState(const int *keepFds, // IN:
1414
size_t numKeepFds) // IN:
1417
struct sigaction sa;
1425
* Disable itimers before resetting the signal handlers.
1426
* Otherwise, the process may still receive timer signals:
1427
* SIGALRM, SIGVTARLM, or SIGPROF.
1429
struct itimerval it;
1430
it.it_value.tv_sec = it.it_value.tv_usec = 0;
1431
it.it_interval.tv_sec = it.it_interval.tv_usec = 0;
1432
setitimer(ITIMER_REAL, &it, NULL);
1433
setitimer(ITIMER_VIRTUAL, &it, NULL);
1434
setitimer(ITIMER_PROF, &it, NULL);
1436
for (s = 1; s <= NSIG; s++) {
1437
sa.sa_handler = SIG_DFL;
1438
sigfillset(&sa.sa_mask);
1439
sa.sa_flags = SA_RESTART;
1440
sigaction(s, &sa, NULL);
1442
for (fd = (int) sysconf(_SC_OPEN_MAX) - 1; fd > STDERR_FILENO; fd--) {
1444
for (i = 0; i < numKeepFds; i++) {
1445
if (fd == keepFds[i]) {
1449
if (i == numKeepFds) {
1454
if (getrlimit(RLIMIT_AS, &rlim) == 0) {
1455
rlim.rlim_cur = rlim.rlim_max;
1456
setrlimit(RLIMIT_AS, &rlim);
1461
* Drop iopl to its default value.
1463
euid = Id_GetEUid();
1464
/* At this point, _unless we are running as root_, we shouldn't have root
1465
privileges --hpreg */
1466
ASSERT(euid != 0 || getuid() == 0);
1470
ASSERT_NOT_IMPLEMENTED(err == 0);
1476
*----------------------------------------------------------------------
1478
* Hostinfo_Execute --
1480
* Start program COMMAND. If WAIT is TRUE, wait for program
1481
* to complete and return exit status.
1484
* Exit status of COMMAND.
1487
* Run a separate program.
1489
*----------------------------------------------------------------------
1492
Hostinfo_Execute(const char *command,
1499
if (command == NULL) {
1510
Hostinfo_ResetProcessState(NULL, 0);
1511
Posix_Execvp(command, args);
1517
if (waitpid(pid, &status, 0) == -1) {
1518
if (errno == ECHILD) {
1519
return 0; // This sucks. We really don't know.
1521
if (errno != EINTR) {
1535
*-----------------------------------------------------------------------------
1537
* Hostinfo_Daemonize --
1539
* Cross-platform daemon(3)-like wrapper.
1541
* Restarts the current process as a daemon, given the path to the
1542
* process (usually from Hostinfo_GetModulePath). This means:
1544
* * You're detached from your parent. (Your parent doesn't
1545
* need to wait for you to exit.)
1546
* * Your process no longer has a controlling terminal or
1548
* * Your stdin/stdout/stderr fds are redirected to /dev/null.
1549
* * Your main() function is called with the specified NULL-terminated
1552
* (Don't forget that the first string in args is argv[0] -- the
1553
* name of the process).
1555
* Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCHDIR, then the
1556
* current directory of the daemon process is set to "/".
1558
* Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCLOSE, then all stdio
1559
* file descriptors of the daemon process are redirected to /dev/null.
1561
* If 'flags' contains HOSTINFO_DAEMONIZE_EXIT, then upon successful
1562
* launch of the daemon, the original process will exit.
1564
* If pidPath is non-NULL, then upon success, writes the PID
1565
* (as a US-ASCII string followed by a newline) of the daemon
1566
* process to that path.
1569
* FALSE if the process could not be daemonized. Err_Errno() contains
1570
* the error on failure.
1571
* TRUE if 'flags' does not contain HOSTINFO_DAEMONIZE_EXIT and
1572
* the process was daemonized.
1573
* Otherwise, if the process was daemonized, this function does
1574
* not return, and flow continues from your own main() function.
1577
* The current process is restarted with the given arguments.
1578
* The process state is reset (see Hostinfo_ResetProcessState).
1579
* A new session is created (so the process has no controlling terminal).
1581
*-----------------------------------------------------------------------------
1585
Hostinfo_Daemonize(const char *path, // IN: NUL-terminated UTF-8
1587
char * const *args, // IN: NULL-terminated UTF-8
1589
HostinfoDaemonizeFlags flags, // IN: flags
1590
const char *pidPath) // IN/OPT: NUL-terminated
1591
// UTF-8 path to write PID
1594
* We use the double-fork method to make a background process whose
1595
* parent is init instead of the original process.
1597
* We do this instead of calling daemon(), because daemon() is
1598
* deprecated on Mac OS 10.5 hosts, and calling it causes a compiler
1601
* We must exec() after forking, because Mac OS library frameworks
1602
* depend on internal Mach ports, which are not correctly propagated
1603
* across fork calls. exec'ing reinitializes the frameworks, which
1604
* causes them to reopen their Mach ports.
1607
int pipeFds[2] = { -1, -1 };
1608
uint32 err = EINVAL;
1609
char *pathLocalEncoding = NULL;
1610
char *pidPathLocalEncoding = NULL;
1611
char **argsLocalEncoding = NULL;
1613
ASSERT_ON_COMPILE(sizeof (errno) <= sizeof err);
1615
if (pipe(pipeFds) == -1) {
1617
Warning("%s: Couldn't create pipe, error %u.\n",
1622
if (fcntl(F_SETFD, pipeFds[1], 1) == -1) {
1624
Warning("%s: Couldn't set close-on-exec for fd %d, error %u.\n",
1625
__FUNCTION__, pipeFds[1], err);
1629
// Convert the strings from UTF-8 before we fork.
1630
pathLocalEncoding = Unicode_GetAllocBytes(path, STRING_ENCODING_DEFAULT);
1631
if (!pathLocalEncoding) {
1632
Warning("%s: Couldn't convert path [%s] to default encoding.\n",
1633
__FUNCTION__, path);
1638
pidPathLocalEncoding =
1639
Unicode_GetAllocBytes(pidPath, STRING_ENCODING_DEFAULT);
1640
if (!pidPathLocalEncoding) {
1641
Warning("%s: Couldn't convert path [%s] to default encoding.\n",
1642
__FUNCTION__, pidPath);
1647
argsLocalEncoding = Unicode_GetAllocList(args, STRING_ENCODING_DEFAULT, -1);
1648
if (!argsLocalEncoding) {
1649
Warning("%s: Couldn't convert arguments to default encoding.\n",
1659
Warning("%s: Couldn't fork first child, error %u.\n",
1663
// We're the first child. Continue on.
1667
// We're the original process. Check if the first child exited.
1669
FileIODescriptor pipeDesc;
1673
pipeDesc = FileIO_CreateFDPosix(pipeFds[0], O_RDONLY);
1675
waitpid(childPid, &status, 0);
1676
if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) {
1677
Warning("%s: Child %d exited with error %d.\n",
1678
__FUNCTION__, childPid, WEXITSTATUS(status));
1680
} else if (WIFSIGNALED(status)) {
1681
Warning("%s: Child %d exited with signal %d.\n",
1682
__FUNCTION__, childPid, WTERMSIG(status));
1687
* Check if the second child exec'ed successfully. If it had
1688
* an error, it will write a uint32 errno to this pipe before
1689
* exiting. Otherwise, its end of the pipe will be closed on
1690
* exec and this call will fail as expected.
1692
if (FileIO_Read(&pipeDesc, &err, sizeof err, NULL) == FILEIO_SUCCESS) {
1693
Warning("%s: Child could not exec %s, error %u.\n",
1694
__FUNCTION__, path, err);
1704
* Close all fds except for the write end of the error pipe (which
1705
* we've already set to close on successful exec).
1707
Hostinfo_ResetProcessState(&pipeFds[1], 1);
1709
if (!(flags & HOSTINFO_DAEMONIZE_NOCLOSE) && setsid() == -1) {
1710
Warning("%s: Couldn't create new session, error %d.\n",
1711
__FUNCTION__, Err_Errno());
1712
_exit(EXIT_FAILURE);
1718
Warning("%s: Couldn't fork second child, error %d.\n",
1719
__FUNCTION__, Err_Errno());
1720
_exit(EXIT_FAILURE);
1723
// We're the second child. Continue on.
1727
* We're the first child. We don't need to exist any more.
1729
* Exiting here causes the second child to be reparented to the
1730
* init process, so the original process doesn't need to wait
1731
* for the child we forked off.
1733
_exit(EXIT_SUCCESS);
1737
* We can't use our i18n wrappers for file manipulation at this
1738
* point, since we've forked; internal library mutexes might be
1741
if (!(flags & HOSTINFO_DAEMONIZE_NOCHDIR) && chdir("/") == -1) {
1742
uint32 err = Err_Errno();
1743
Warning("%s: Couldn't chdir to /, error %u.\n",
1745
// Let the original process know we failed to chdir.
1746
if (write(pipeFds[1], &err, sizeof err) == -1) {
1747
Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
1750
_exit(EXIT_FAILURE);
1753
if (!(flags & HOSTINFO_DAEMONIZE_NOCLOSE)) {
1756
fd = open(_PATH_DEVNULL, O_RDONLY);
1758
dup2(fd, STDIN_FILENO);
1762
fd = open(_PATH_DEVNULL, O_WRONLY);
1764
dup2(fd, STDOUT_FILENO);
1765
dup2(fd, STDERR_FILENO);
1775
FileIODescriptor pidDesc;
1777
ASSERT_ON_COMPILE(sizeof (pid_t) <= sizeof pid);
1778
ASSERT(pidPathLocalEncoding);
1780
// See above comment about how we can't use our i18n wrappers here.
1781
pidPathFd = open(pidPathLocalEncoding, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1783
if (pidPathFd == -1) {
1785
Warning("%s: Couldn't open PID path [%s], error %d.\n",
1786
__FUNCTION__, pidPath, err);
1787
if (write(pipeFds[1], &err, sizeof err) == -1) {
1788
Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
1791
_exit(EXIT_FAILURE);
1795
pidStringLen = Str_Sprintf(pidString, sizeof pidString,
1796
"%"FMT64"d\n", pid);
1797
if (pidStringLen <= 0) {
1799
if (write(pipeFds[1], &err, sizeof err) == -1) {
1800
Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
1803
_exit(EXIT_FAILURE);
1806
pidDesc = FileIO_CreateFDPosix(pidPathFd, O_WRONLY);
1808
if (FileIO_Write(&pidDesc, pidString, pidStringLen, NULL) !=
1811
Warning("%s: Couldn't write PID to path [%s], error %d.\n",
1812
__FUNCTION__, pidPath, err);
1813
if (write(pipeFds[1], &err, sizeof err) == -1) {
1814
Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
1817
_exit(EXIT_FAILURE);
1823
if (execv(pathLocalEncoding, argsLocalEncoding) == -1) {
1824
uint32 err = Err_Errno();
1825
Warning("%s: Couldn't exec %s, error %u.\n",
1826
__FUNCTION__, path, err);
1827
// Let the original process know we failed to exec.
1828
if (write(pipeFds[1], &err, sizeof err) == -1) {
1829
Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
1832
_exit(EXIT_FAILURE);
1838
if (pipeFds[0] != -1) {
1841
if (pipeFds[1] != -1) {
1844
Util_FreeStringList(argsLocalEncoding, -1);
1845
free(pidPathLocalEncoding);
1846
free(pathLocalEncoding);
1849
if (flags & HOSTINFO_DAEMONIZE_EXIT) {
1850
_exit(EXIT_SUCCESS);
1856
File_Unlink(pidPath);
1865
*----------------------------------------------------------------------
1867
* Hostinfo_OSIsSMP --
1869
* Host OS SMP capability.
1872
* TRUE is host OS is SMP capable.
1877
*----------------------------------------------------------------------
1881
Hostinfo_OSIsSMP(void)
1885
#if defined(__APPLE__)
1886
size_t ncpuSize = sizeof ncpu;
1888
if (sysctlbyname("hw.ncpu", &ncpu, &ncpuSize, NULL, 0) == -1) {
1893
ncpu = Hostinfo_NumCPUs();
1895
if (ncpu == 0xFFFFFFFF) {
1900
return ncpu > 1 ? TRUE : FALSE;
1904
*-----------------------------------------------------------------------------
1906
* Hostinfo_GetModulePath --
1908
* Retrieve the full path to the executable. Not supported under VMvisor.
1910
* Note: If your process is running with elevated privileges
1911
* (setuid/setgid), treat the path returned by this function as
1912
* untrusted (for example, do not pass it to exec or open).
1914
* This function returns a path that is under the control of the
1915
* user. An attacker could manipulate the path returned by this
1916
* function to elevate privileges.
1919
* On success: The allocated, NUL-terminated file path.
1920
* Note: This path can be a symbolic or hard link; it's just one
1921
* possible path to access the executable.
1928
*-----------------------------------------------------------------------------
1932
Hostinfo_GetModulePath(uint32 priv)
1936
#if defined(__APPLE__)
1937
uint32_t pathSize = FILE_MAXPATH;
1942
if ((priv != HGMP_PRIVILEGE) && (priv != HGMP_NO_PRIVILEGE)) {
1943
Warning("%s: invalid privilege parameter\n", __FUNCTION__);
1947
#if defined(__APPLE__)
1948
path = Util_SafeMalloc(pathSize);
1949
if (_NSGetExecutablePath(path, &pathSize)) {
1950
Warning(LGPFX" %s: _NSGetExecutablePath failed.\n", __FUNCTION__);
1956
#if defined(VMX86_SERVER)
1957
if (HostType_OSIsVMK()) {
1962
// "/proc/self/exe" only exists on Linux 2.2+.
1963
ASSERT(Hostinfo_OSVersion(0) >= 2 && Hostinfo_OSVersion(1) >= 2);
1965
if (priv == HGMP_PRIVILEGE) {
1966
uid = Id_BeginSuperUser();
1969
path = Posix_ReadLink("/proc/self/exe");
1971
if (priv == HGMP_PRIVILEGE) {
1972
Id_EndSuperUser(uid);
1976
Warning(LGPFX" %s: readlink failed: %s\n",
1977
__FUNCTION__, Err_ErrString());
1986
*----------------------------------------------------------------------
1988
* Hostinfo_TouchBackDoor --
1990
* Access the backdoor. This is used to determine if we are
1991
* running in a VM or on a physical host. On a physical host
1992
* this should generate a GP which we catch and thereby determine
1993
* that we are not in a VM. However some OSes do not handle the
1994
* GP correctly and the process continues running returning garbage.
1995
* In this case we check the EBX register which should be
1996
* BDOOR_MAGIC if the IN was handled in a VM. Based on this we
1997
* return either TRUE or FALSE.
2000
* TRUE if we succesfully accessed the backdoor, FALSE or segfault
2004
* Exception if not in a VM.
2006
*----------------------------------------------------------------------
2010
Hostinfo_TouchBackDoor(void)
2013
* XXX: This can cause Apple's Crash Reporter to erroneously display
2014
* a crash, even though the process has caught the SIGILL and handled
2017
* It's also annoying in gdb, so we'll turn it off in devel builds.
2019
#if !defined(__APPLE__) && !defined(VMX86_DEVEL)
2024
__asm__ __volatile__(
2025
# if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
2026
"xchgl %%ebx, %1" "\n\t"
2027
"inl %%dx, %%eax" "\n\t"
2037
: "0" (BDOOR_MAGIC),
2039
"2" (BDOOR_CMD_GETVERSION),
2042
if (ebx == BDOOR_MAGIC) {
2051
*-----------------------------------------------------------------------------
2053
* Hostinfo_GetUser --
2055
* Return current user name, or NULL if can't tell.
2056
* XXX Not thread-safe (somebody could do a setenv()). --hpreg
2059
* User name. Must be free()d by caller.
2064
*-----------------------------------------------------------------------------
2070
char buffer[BUFSIZ];
2072
struct passwd *ppw = &pw;
2074
Unicode name = NULL;
2076
if ((Posix_Getpwuid_r(getuid(), &pw, buffer, sizeof buffer, &ppw) == 0) &&
2079
name = Unicode_Duplicate(ppw->pw_name);
2084
env = Posix_Getenv("USER");
2086
name = Unicode_Duplicate(env);
2093
*-----------------------------------------------------------------------------
2095
* Hostinfo_LogMemUsage --
2096
* Log system memory usage.
2099
* System memory usage is logged.
2104
*-----------------------------------------------------------------------------
2108
Hostinfo_LogMemUsage(void)
2110
int fd = Posix_Open("/proc/self/statm", O_RDONLY);
2116
len = read(fd, buf, sizeof buf);
2122
buf[len < sizeof buf ? len : sizeof buf - 1] = '\0';
2124
sscanf(buf, "%d %d %d %d %d %d %d",
2125
&a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6]);
2127
Log("RUSAGE size=%d resident=%d share=%d trs=%d lrs=%d drs=%d dt=%d\n",
2128
a[0], a[1], a[2], a[3], a[4], a[5], a[6]);