~n-muench/ubuntu/quantal/open-vm-tools/open-vm-tools.may2.sid-sync

« back to all changes in this revision

Viewing changes to lib/user/hostinfoPosix.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-05-30 09:48:43 UTC
  • mfrom: (1.1.5 upstream) (2.4.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090530094843-gdpza57r5iqsf124
Tags: 2009.05.22-167859-1
MergingĀ upstreamĀ versionĀ 2009.05.22-167859.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*********************************************************
2
 
 * Copyright (C) 1998 VMware, Inc. All rights reserved.
3
 
 *
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.
7
 
 *
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.
12
 
 *
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.
16
 
 *
17
 
 *********************************************************/
18
 
 
19
 
/*
20
 
 * hostinfoPosix.c --
21
 
 *
22
 
 *   Interface to host-specific information functions for Posix hosts
23
 
 *   
24
 
 *   I created this file for this only reason: the functions it contains should
25
 
 *   be callable by _any_ VMware userland program --hpreg
26
 
 *   
27
 
 */
28
 
 
29
 
#include <stdlib.h>
30
 
#include <stdio.h>
31
 
#include <unistd.h>
32
 
#include <string.h>
33
 
#include <ctype.h>
34
 
#include <sys/utsname.h>
35
 
#include <netdb.h>
36
 
#include <fcntl.h>
37
 
#include <limits.h>
38
 
#include <errno.h>
39
 
#include <sys/stat.h>
40
 
#include <sys/types.h>
41
 
#include <sys/wait.h>
42
 
#include <signal.h>
43
 
#include <sys/time.h>
44
 
#include <sys/timeb.h>
45
 
#include <pwd.h>
46
 
#include <sys/resource.h>
47
 
#if defined(__APPLE__)
48
 
#define SYS_NMLN _SYS_NAMELEN
49
 
#include <assert.h>
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
63
 
#  else
64
 
#     define RLIMIT_AS RLIMIT_RSS
65
 
#  endif
66
 
#endif
67
 
#else
68
 
#if !defined(USING_AUTOCONF) || defined(HAVE_SYS_VFS_H)
69
 
#include <sys/vfs.h>
70
 
#endif
71
 
#if !defined(sun) && (!defined(USING_AUTOCONF) || (defined(HAVE_SYS_IO_H) && defined(HAVE_SYS_SYSINFO_H)))
72
 
#include <sys/io.h>
73
 
#include <sys/sysinfo.h>
74
 
#ifndef HAVE_SYSINFO
75
 
#define HAVE_SYSINFO 1
76
 
#endif
77
 
#endif
78
 
#endif
79
 
 
80
 
#if defined(__APPLE__) || defined(__FreeBSD__)
81
 
#include <paths.h>
82
 
#endif
83
 
 
84
 
#ifndef _PATH_DEVNULL
85
 
#define _PATH_DEVNULL "/dev/null"
86
 
#endif
87
 
 
88
 
#include "vmware.h"
89
 
#include "hostType.h"
90
 
#include "hostinfo.h"
91
 
#include "vm_version.h"
92
 
#include "str.h"
93
 
#include "msg.h"
94
 
#include "log.h"
95
 
#include "posix.h"
96
 
#include "file.h"
97
 
#include "backdoor_def.h"
98
 
#include "util.h"
99
 
#include "vmstdio.h"
100
 
#include "su.h"
101
 
#include "vm_atomic.h"
102
 
#include "x86cpuid.h"
103
 
#include "syncMutex.h"
104
 
#include "unicode.h"
105
 
 
106
 
#ifdef VMX86_SERVER
107
 
#include "uwvmkAPI.h"
108
 
#include "uwvmk.h"
109
 
#include "vmkSyscall.h"
110
 
#endif
111
 
 
112
 
#define LGPFX "HOSTINFO:"
113
 
#define MAX_LINE_LEN 128
114
 
 
115
 
/*
116
 
 * Global data
117
 
 */
118
 
 
119
 
// nothing
120
 
 
121
 
 
122
 
/*
123
 
 * Local functions
124
 
 */
125
 
 
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__
132
 
 
133
 
 
134
 
/*
135
 
 *-----------------------------------------------------------------------------
136
 
 *
137
 
 * HostinfoGetLoadAverage --
138
 
 *
139
 
 *      Returns system average load.
140
 
 *
141
 
 * Results:
142
 
 *      TRUE on success, FALSE otherwise.
143
 
 *
144
 
 * Side effects:
145
 
 *      None.
146
 
 *
147
 
 *-----------------------------------------------------------------------------
148
 
 */
149
 
 
150
 
static Bool
151
 
HostinfoGetLoadAverage(float *avg0,  // IN/OUT
152
 
                       float *avg1,  // IN/OUT
153
 
                       float *avg2)  // IN/OUT
154
 
{
155
 
   /* getloadavg(3) was introduced with glibc 2.2 */
156
 
#if defined(GLIBC_VERSION_22) || defined(__APPLE__)
157
 
   double avg[3];
158
 
   int res;
159
 
 
160
 
   res = getloadavg(avg, 3);
161
 
   if (res < 3) {
162
 
      NOT_TESTED_ONCE();
163
 
      return FALSE;
164
 
   }
165
 
 
166
 
   if (avg0) {
167
 
      *avg0 = (float) avg[0];
168
 
   }
169
 
   if (avg1) {
170
 
      *avg1 = (float) avg[1];
171
 
   }
172
 
   if (avg2) {
173
 
      *avg2 = (float) avg[2];
174
 
   }
175
 
   return TRUE;
176
 
#else
177
 
   /* 
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.
182
 
    */
183
 
   NOT_IMPLEMENTED();
184
 
   return FALSE;
185
 
#endif
186
 
}
187
 
 
188
 
 
189
 
/*
190
 
 *-----------------------------------------------------------------------------
191
 
 *
192
 
 * Hostinfo_GetLoadAverage --
193
 
 *
194
 
 *      Returns system average load * 100.
195
 
 *
196
 
 * Results:
197
 
 *      TRUE/FALSE
198
 
 *
199
 
 * Side effects:
200
 
 *      None.
201
 
 *
202
 
 *-----------------------------------------------------------------------------
203
 
 */
204
 
 
205
 
Bool
206
 
Hostinfo_GetLoadAverage(uint32 *avg)      // IN/OUT
207
 
{
208
 
   float avg0;
209
 
 
210
 
   if (!HostinfoGetLoadAverage(&avg0, NULL, NULL)) {
211
 
      return FALSE;
212
 
   }
213
 
   *avg = (uint32) 100 * avg0;
214
 
   return TRUE;
215
 
}
216
 
 
217
 
 
218
 
/*
219
 
 *-----------------------------------------------------------------------------
220
 
 *
221
 
 * Hostinfo_LogLoadAverage --
222
 
 *
223
 
 *      Logs system average load.
224
 
 *
225
 
 * Results:
226
 
 *      None.
227
 
 *
228
 
 * Side effects:
229
 
 *      None.
230
 
 *
231
 
 *-----------------------------------------------------------------------------
232
 
 */
233
 
 
234
 
void
235
 
Hostinfo_LogLoadAverage(void)
236
 
{
237
 
   float avg0, avg1, avg2;
238
 
 
239
 
   if (!HostinfoGetLoadAverage(&avg0, &avg1, &avg2)) {
240
 
      return;
241
 
   }
242
 
   Log("LOADAVG: %.2f %.2f %.2f\n", avg0, avg1, avg2);
243
 
}
244
 
 
245
 
#if defined(__APPLE__)
246
 
/*
247
 
 *-----------------------------------------------------------------------------
248
 
 *
249
 
 * HostinfoMacAbsTimeNS --
250
 
 *
251
 
 *      Return the Mac OS absolute time.
252
 
 *
253
 
 * Results:
254
 
 *      The absolute time in nanoseconds is returned. This time is documented
255
 
 *      to NEVER go backwards.
256
 
 *
257
 
 * Side effects:
258
 
 *      None.
259
 
 *
260
 
 *-----------------------------------------------------------------------------
261
 
 */
262
 
 
263
 
static inline VmTimeType
264
 
HostinfoMacAbsTimeNS(void)
265
 
{
266
 
   VmTimeType raw;
267
 
   mach_timebase_info_data_t *ptr;
268
 
   static Atomic_Ptr atomic; /* Implicitly initialized to NULL. --mbellon */
269
 
 
270
 
   /* Insure that the time base values are correct. */
271
 
   ptr = (mach_timebase_info_data_t *) Atomic_ReadPtr(&atomic);
272
 
 
273
 
   if (ptr == NULL) {
274
 
      char *p;
275
 
 
276
 
      p = Util_SafeMalloc(sizeof(mach_timebase_info_data_t));
277
 
 
278
 
      mach_timebase_info((mach_timebase_info_data_t *) p);
279
 
 
280
 
      if (Atomic_ReadIfEqualWritePtr(&atomic, NULL, p)) {
281
 
         free(p);
282
 
      }
283
 
 
284
 
      ptr = (mach_timebase_info_data_t *) Atomic_ReadPtr(&atomic);
285
 
   }
286
 
 
287
 
   raw = mach_absolute_time();
288
 
 
289
 
   if ((ptr->numer == 1) && (ptr->denom == 1)) {
290
 
      /* The scaling values are unity, save some time/arithmetic */
291
 
      return raw;
292
 
   } else {
293
 
      /* The scaling values are not unity. Prevent overflow when scaling */
294
 
      return ((double) raw) * (((double) ptr->numer) / ((double) ptr->denom));
295
 
   }
296
 
}
297
 
#endif
298
 
 
299
 
 
300
 
/*
301
 
 *-----------------------------------------------------------------------------
302
 
 *
303
 
 * HostinfoRawSystemTimerUS --
304
 
 *
305
 
 *      Obtain the raw system timer value.
306
 
 *
307
 
 * Results:
308
 
 *      Relative time in microseconds or zero if a failure.
309
 
 *
310
 
 * Side effects:
311
 
 *      None.
312
 
 *
313
 
 *-----------------------------------------------------------------------------
314
 
 */
315
 
 
316
 
VmTimeType
317
 
Hostinfo_RawSystemTimerUS(void)
318
 
{
319
 
#if defined(__APPLE__)
320
 
   return HostinfoMacAbsTimeNS() / 1000ULL;
321
 
#else
322
 
#if defined(VMX86_SERVER)
323
 
   if (HostType_OSIsPureVMK()) {
324
 
      uint64 uptime;
325
 
      VMK_ReturnStatus status;
326
 
 
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!
331
 
      }
332
 
 
333
 
      return uptime;
334
 
   } else {
335
 
#endif /* ifdef VMX86_SERVER */
336
 
      struct timeval tval;
337
 
 
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!
342
 
      }
343
 
      /* Convert into microseconds */
344
 
      return (((VmTimeType)tval.tv_sec) * 1000000 + tval.tv_usec);
345
 
#if defined(VMX86_SERVER)
346
 
   }
347
 
#endif /* ifdef VMX86_SERVER */
348
 
#endif /* ifdef __APPLE__ */
349
 
}
350
 
 
351
 
 
352
 
/*
353
 
 *-----------------------------------------------------------------------------
354
 
 *
355
 
 * Hostinfo_SystemTimerUS --
356
 
 *
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.
361
 
 *
362
 
 *      This timer is documented to never go backwards.
363
 
 *
364
 
 * Results:
365
 
 *      Relative time in microseconds or zero if a failure.
366
 
 *
367
 
 *      Please note that the actual resolution of this "clock" is undefined -
368
 
 *      it varies between OSen and OS versions.
369
 
 *
370
 
 * Side effects:
371
 
 *      None.
372
 
 *
373
 
 *-----------------------------------------------------------------------------
374
 
 */
375
 
 
376
 
VmTimeType
377
 
Hostinfo_SystemTimerUS(void)
378
 
{
379
 
   SyncMutex *lck;
380
 
   VmTimeType curTime;
381
 
   VmTimeType newTime;
382
 
 
383
 
   static Atomic_Ptr lckStorage;
384
 
   static VmTimeType lastTimeBase;
385
 
   static VmTimeType lastTimeRead;
386
 
   static VmTimeType lastTimeReset;
387
 
 
388
 
   /* Get and take lock. */
389
 
   lck = SyncMutex_CreateSingleton(&lckStorage);
390
 
   SyncMutex_Lock(lck);
391
 
 
392
 
   curTime = Hostinfo_RawSystemTimerUS();
393
 
 
394
 
   if (curTime == 0) {
395
 
      newTime = 0;
396
 
      goto exit;
397
 
   }
398
 
 
399
 
   /*
400
 
    * Don't let time be negative or go backward.  We do this by
401
 
    * tracking a base and moving foward from there.
402
 
    */
403
 
 
404
 
   newTime = lastTimeBase + (curTime - lastTimeReset);
405
 
 
406
 
   if (newTime < lastTimeRead) {
407
 
      lastTimeReset = curTime;
408
 
      lastTimeBase = lastTimeRead + 1;
409
 
      newTime = lastTimeBase + (curTime - lastTimeReset);
410
 
   }
411
 
 
412
 
   lastTimeRead = newTime;
413
 
 
414
 
exit:
415
 
   /* Release lock. */
416
 
   SyncMutex_Unlock(lck);
417
 
 
418
 
   return newTime;
419
 
}
420
 
 
421
 
/*
422
 
 *-----------------------------------------------------------------------------
423
 
 *
424
 
 * Hostinfo_SystemUpTime --
425
 
 *
426
 
 *      Return system uptime in microseconds.
427
 
 *
428
 
 *      Please note that the actual resolution of this "clock" is undefined -
429
 
 *      it varies between OSen and OS versions. Use Hostinfo_SystemTimerUS
430
 
 *      whenever possible.
431
 
 *
432
 
 * Results:
433
 
 *      System uptime in microseconds or zero in case of a failure.
434
 
 *
435
 
 * Side effects:
436
 
 *      None.
437
 
 *
438
 
 *-----------------------------------------------------------------------------
439
 
 */
440
 
 
441
 
VmTimeType
442
 
Hostinfo_SystemUpTime(void)
443
 
{
444
 
#if defined(__APPLE__)
445
 
   return HostinfoMacAbsTimeNS() / 1000ULL;
446
 
#elif defined(VMX86_SERVER)
447
 
   uint64 uptime;
448
 
   VMK_ReturnStatus status;
449
 
 
450
 
   if (VmkSyscall_Init(FALSE, NULL, 0)) {
451
 
      status = CosVmnix_GetUptimeUS(&uptime);
452
 
      if (status == VMK_OK) {
453
 
         return uptime;
454
 
      }
455
 
   }
456
 
 
457
 
   return 0;
458
 
#elif defined(__linux__)
459
 
   int res;
460
 
   double uptime;
461
 
   int fd;
462
 
   char buf[256];
463
 
 
464
 
   static Atomic_Int fdStorage = { -1 };
465
 
   static Atomic_uint32 logFailedPread = { 1 };
466
 
 
467
 
   fd = Atomic_ReadInt(&fdStorage);
468
 
 
469
 
   /* Do we need to open the file the first time through? */
470
 
   if (UNLIKELY(fd == -1)) {
471
 
      fd = open("/proc/uptime", O_RDONLY);
472
 
 
473
 
      if (fd == -1) {
474
 
         Warning(LGPFX" Failed to open /proc/uptime: %s\n", Msg_ErrString());
475
 
         return 0;
476
 
      }
477
 
 
478
 
      /* Try to swap ours in. If we lose the race, close our fd */
479
 
      if (Atomic_ReadIfEqualWriteInt(&fdStorage, -1, fd) != -1) {
480
 
         close(fd);
481
 
      }
482
 
 
483
 
      /* Get the winning fd - either ours or theirs, doesn't matter anymore */
484
 
      fd = Atomic_ReadInt(&fdStorage);
485
 
   }
486
 
 
487
 
   ASSERT(fd != -1);
488
 
 
489
 
   res = pread(fd, buf, sizeof buf - 1, 0);
490
 
   if (res == -1) {
491
 
      /*
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.
496
 
       */
497
 
 
498
 
      if (Atomic_ReadIfEqualWrite(&logFailedPread, 1, 0) == 1) {
499
 
         Warning(LGPFX" Failed to pread /proc/uptime: %s\n", Msg_ErrString());
500
 
      }
501
 
      fd = open("/proc/uptime", O_RDONLY);
502
 
      if (fd == -1) {
503
 
         Warning(LGPFX" Failed to retry open /proc/uptime: %s\n",
504
 
                 Msg_ErrString());
505
 
         return 0;
506
 
      }
507
 
      res = read(fd, buf, sizeof buf - 1);
508
 
      close(fd);
509
 
      if (res == -1) {
510
 
         Warning(LGPFX" Failed to read /proc/uptime: %s\n", Msg_ErrString());
511
 
         return 0;
512
 
      }
513
 
   }
514
 
   ASSERT(res < sizeof buf);
515
 
   buf[res] = '\0';
516
 
 
517
 
   if (sscanf(buf, "%lf", &uptime) != 1) {
518
 
      Warning(LGPFX" Failed to parse /proc/uptime\n");
519
 
      return 0;
520
 
   }
521
 
 
522
 
   return uptime * 1000 * 1000;
523
 
#else
524
 
NOT_IMPLEMENTED();
525
 
#endif
526
 
}
527
 
 
528
 
 
529
 
/*
530
 
 *-----------------------------------------------------------------------------
531
 
 *
532
 
 * Hostinfo_NameGet --
533
 
 *
534
 
 *      Return the fully qualified host name of the host.
535
 
 *      Thread-safe. --hpreg
536
 
 *
537
 
 * Results:
538
 
 *      The (memorized) name on success
539
 
 *      NULL on failure
540
 
 *
541
 
 * Side effects:
542
 
 *      A host name resolution can occur.
543
 
 *
544
 
 *-----------------------------------------------------------------------------
545
 
 */
546
 
 
547
 
Unicode
548
 
Hostinfo_NameGet(void)
549
 
{
550
 
   Unicode result;
551
 
 
552
 
   static Atomic_Ptr state; /* Implicitly initialized to NULL. --hpreg */
553
 
 
554
 
   result = Atomic_ReadPtr(&state);
555
 
 
556
 
   if (UNLIKELY(result == NULL)) {
557
 
      Unicode before;
558
 
 
559
 
      result = Hostinfo_HostName();
560
 
 
561
 
      before = Atomic_ReadIfEqualWritePtr(&state, NULL, result);
562
 
 
563
 
      if (before) {
564
 
         Unicode_Free(result);
565
 
 
566
 
         result = before;
567
 
      }
568
 
   }
569
 
 
570
 
   return result;
571
 
}
572
 
 
573
 
 
574
 
#ifdef VMX86_SERVER
575
 
/*
576
 
 *----------------------------------------------------------------------
577
 
 *
578
 
 * HostinfoReadProc --
579
 
 *
580
 
 *      Depending on what string is passed to it, this function parses the
581
 
 *      /proc/vmware/sched/ncpus node and returns the requested value.
582
 
 *
583
 
 * Results:
584
 
 *      A postive value on success, -1 (0xFFFFFFFF) on failure.
585
 
 *
586
 
 * Side effects:
587
 
 *      None.
588
 
 *
589
 
 *----------------------------------------------------------------------
590
 
 */
591
 
 
592
 
static INLINE uint32
593
 
HostinfoReadProc(const char *str)
594
 
{
595
 
   /* XXX this should use sysinfo!! (bug 59849)
596
 
    */
597
 
   FILE *f;
598
 
   char *line;
599
 
   uint32 count;
600
 
 
601
 
   ASSERT(!strcmp("logical", str) || !strcmp("cores", str) || !strcmp("packages", str)); 
602
 
 
603
 
   ASSERT(!HostType_OSIsVMK()); // Don't use /proc/vmware
604
 
 
605
 
   f = Posix_Fopen("/proc/vmware/sched/ncpus", "r");
606
 
   if (f != NULL) {
607
 
      while (StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) {
608
 
         if (strstr(line, str)) {
609
 
            if (sscanf(line, "%d ", &count) == 1) {
610
 
               free(line);
611
 
               break;
612
 
            }
613
 
         }
614
 
         free(line);
615
 
      }
616
 
      fclose(f);
617
 
 
618
 
      if (count > 0) {
619
 
         return count;
620
 
      }
621
 
   }
622
 
 
623
 
   return -1;
624
 
}
625
 
 
626
 
 
627
 
/*
628
 
 *----------------------------------------------------------------------
629
 
 *
630
 
 * Hostinfo_HTDisabled --
631
 
 *
632
 
 *      Figure out if hyperthreading is enabled
633
 
 *
634
 
 * Results:
635
 
 *      TRUE if hyperthreading is disabled, FALSE otherwise
636
 
 *
637
 
 * Side effects:
638
 
 *      None.
639
 
 *
640
 
 *----------------------------------------------------------------------
641
 
 */
642
 
 
643
 
Bool
644
 
Hostinfo_HTDisabled(void)
645
 
{
646
 
   static uint32 logical = 0, cores = 0;
647
 
 
648
 
   if (HostType_OSIsVMK()) {
649
 
      VMK_ReturnStatus status = VMKernel_HTEnabledCPU();
650
 
      if (status != VMK_OK) {
651
 
         return TRUE;
652
 
      } else {
653
 
         return FALSE;
654
 
      }
655
 
   }
656
 
 
657
 
   if (logical == 0 && cores == 0) {
658
 
      logical = HostinfoReadProc("logical");
659
 
      cores = HostinfoReadProc("cores");
660
 
      if (logical <= 0 || cores <= 0) {
661
 
         logical = cores = 0;
662
 
      }
663
 
   }
664
 
 
665
 
   return logical == cores;
666
 
}
667
 
#endif /*ifdef VMX86_SERVER*/
668
 
 
669
 
 
670
 
/*
671
 
 *-----------------------------------------------------------------------------
672
 
 *
673
 
 * Hostinfo_NumCPUs --
674
 
 *
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.
679
 
 *
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
683
 
 *      purposes.
684
 
 *
685
 
 * Results:
686
 
 *      On success, the number of CPUs (> 0) the host tells us we have.
687
 
 *      On failure, 0xFFFFFFFF (-1).
688
 
 *
689
 
 * Side effects:
690
 
 *      None
691
 
 *
692
 
 *-----------------------------------------------------------------------------
693
 
 */
694
 
 
695
 
uint32
696
 
Hostinfo_NumCPUs(void)
697
 
{
698
 
#if defined(__APPLE__)
699
 
   uint32 out;
700
 
   size_t outSize = sizeof out;
701
 
 
702
 
   /*
703
 
    * Quoting sys/sysctl.h:
704
 
    * "
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
707
 
    * 32 bit numbers.
708
 
    * ...
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.
713
 
    * "
714
 
    *
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
718
 
    */
719
 
 
720
 
   if (sysctlbyname("hw.activecpu", &out, &outSize, NULL, 0) == -1) {
721
 
      return -1;
722
 
   }
723
 
 
724
 
   return out;
725
 
#elif defined(__FreeBSD__)
726
 
   uint32 out;
727
 
   size_t outSize = sizeof out;
728
 
 
729
 
#if __FreeBSD__version >= 500019
730
 
   if (sysctlbyname("kern.smp.cpus", &out, &outSize, NULL, 0) == -1) {
731
 
      return -1;
732
 
   }
733
 
#else
734
 
   if (sysctlbyname("machdep.smp_cpus", &out, &outSize, NULL, 0) == -1) {
735
 
      if (errno == ENOENT) {
736
 
         out = 1;
737
 
      } else {
738
 
         return -1;
739
 
      }
740
 
   }
741
 
#endif
742
 
 
743
 
   return out;
744
 
#else
745
 
   static int count = 0;
746
 
 
747
 
   if (count <= 0) {
748
 
#ifdef VMX86_SERVER
749
 
      if (HostType_OSIsVMK()) {
750
 
         VMK_ReturnStatus status = VMKernel_GetNumCPUsUsed(&count);
751
 
         if (status != VMK_OK) {
752
 
            count = 0;
753
 
            return -1;
754
 
         }
755
 
      } else {
756
 
         count = HostinfoReadProc("logical");
757
 
         if (count <= 0) {
758
 
            count = 0;
759
 
            return -1;
760
 
         }
761
 
      }
762
 
#else /* ifdef VMX86_SERVER */
763
 
      FILE *f;
764
 
      char *line;
765
 
 
766
 
      f = Posix_Fopen("/proc/cpuinfo", "r");
767
 
      if (f == NULL) { 
768
 
         Msg_Post(MSG_ERROR,
769
 
                  MSGID(hostlinux.opencpuinfo)
770
 
                  "Could not open /proc/cpuinfo.\n");
771
 
         return -1;
772
 
      }
773
 
      
774
 
      while (StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) {
775
 
         if (strncmp(line, "processor", strlen("processor")) == 0) {
776
 
            count++;
777
 
         }
778
 
         free(line);
779
 
      }
780
 
      
781
 
      fclose(f);
782
 
      
783
 
      if (count == 0) {
784
 
         Msg_Post(MSG_ERROR,
785
 
                  MSGID(hostlinux.readcpuinfo)
786
 
                  "Could not determine the number of processors from "
787
 
                  "/proc/cpuinfo.\n");
788
 
         return -1;
789
 
      }
790
 
#endif /* ifdef VMX86_SERVER */
791
 
   }
792
 
 
793
 
   return count;
794
 
#endif
795
 
}
796
 
 
797
 
 
798
 
/*
799
 
 *-----------------------------------------------------------------------------
800
 
 *
801
 
 * Hostinfo_GetRatedCpuMhz --
802
 
 *
803
 
 *      Get the rated CPU speed of a given processor. 
804
 
 *      Return value is in MHz.
805
 
 *
806
 
 * Results:
807
 
 *      TRUE on success, FALSE on failure
808
 
 *
809
 
 * Side effects:
810
 
 *      None.
811
 
 *
812
 
 *-----------------------------------------------------------------------------
813
 
 */
814
 
 
815
 
Bool
816
 
Hostinfo_GetRatedCpuMhz(int32 cpuNumber, // IN
817
 
                        uint32 *mHz)     // OUT
818
 
{
819
 
#if defined(__APPLE__) || defined(__FreeBSD__)
820
 
 
821
 
#  if defined(__APPLE__)
822
 
#     define CPUMHZ_SYSCTL_NAME "hw.cpufrequency_max"
823
 
#  elif __FreeBSD__version >= 50011
824
 
#     define CPUMHZ_SYSCTL_NAME "hw.clockrate"
825
 
#  endif
826
 
 
827
 
#  if defined(CPUMHZ_SYSCTL_NAME)
828
 
   uint32 hz;
829
 
   size_t hzSize = sizeof hz;
830
 
 
831
 
   // 'cpuNumber' is ignored: Intel Macs are always perfectly symetric.
832
 
 
833
 
   if (sysctlbyname(CPUMHZ_SYSCTL_NAME, &hz, &hzSize, NULL, 0) == -1) {
834
 
      return FALSE;
835
 
   }
836
 
 
837
 
   *mHz = hz / 1000000;
838
 
   return TRUE;
839
 
#  else
840
 
   return FALSE;
841
 
#  endif
842
 
#else
843
 
   float fMhz = 0;
844
 
   char *readVal = HostinfoGetCpuInfo(cpuNumber, "cpu MHz");
845
 
   
846
 
   if (readVal == NULL) {
847
 
      return FALSE;
848
 
   }
849
 
   
850
 
   if (sscanf(readVal, "%f", &fMhz) == 1) {
851
 
      *mHz = (unsigned int)(fMhz + 0.5);
852
 
   }
853
 
   free(readVal);
854
 
   return TRUE;
855
 
#endif
856
 
}
857
 
 
858
 
 
859
 
/*
860
 
 *-----------------------------------------------------------------------------
861
 
 *
862
 
 * Hostinfo_GetCpuDescription --
863
 
 *
864
 
 *      Get the descriptive name associated with a given CPU.
865
 
 *
866
 
 * Results:
867
 
 *      On success: Allocated, NUL-terminated string.
868
 
 *      On failure: NULL.
869
 
 *
870
 
 * Side effects:
871
 
 *      None.
872
 
 *
873
 
 *-----------------------------------------------------------------------------
874
 
 */
875
 
 
876
 
char *
877
 
Hostinfo_GetCpuDescription(uint32 cpuNumber) // IN
878
 
{
879
 
#if defined(__APPLE__) || defined(__FreeBSD__)
880
 
#  if defined(__APPLE__)
881
 
#     define CPUDESC_SYSCTL_NAME "machdep.cpu.brand_string"
882
 
#  else
883
 
#     define CPUDESC_SYSCTL_NAME "hw.model"
884
 
#  endif
885
 
 
886
 
   char *desc;
887
 
   size_t descSize;
888
 
 
889
 
   // 'cpuNumber' is ignored: Intel Macs are always perfectly symetric.
890
 
 
891
 
   if (sysctlbyname(CPUDESC_SYSCTL_NAME, NULL, &descSize, NULL, 0)
892
 
          == -1) {
893
 
      return NULL;
894
 
   }
895
 
 
896
 
   desc = malloc(descSize);
897
 
   if (!desc) {
898
 
      return NULL;
899
 
   }
900
 
 
901
 
   if (sysctlbyname(CPUDESC_SYSCTL_NAME, desc, &descSize, NULL, 0)
902
 
          == -1) {
903
 
      free(desc);
904
 
      return NULL;
905
 
   }
906
 
 
907
 
   return desc;
908
 
#else
909
 
#ifdef VMX86_SERVER
910
 
   if (HostType_OSIsVMK()) {
911
 
      char mName[48];
912
 
 
913
 
      // VMKernel treats mName as an in/out parameter so terminate it.
914
 
      mName[0] = '\0';
915
 
      if (VMKernel_GetCPUModelName(mName, cpuNumber, sizeof(mName)) == VMK_OK) {
916
 
         mName[sizeof(mName) - 1] = '\0';
917
 
         return strdup(mName);
918
 
      }
919
 
      return NULL;
920
 
   }
921
 
#endif
922
 
   return HostinfoGetCpuInfo(cpuNumber, "model name");
923
 
#endif
924
 
}
925
 
 
926
 
 
927
 
#if !defined(__APPLE__)
928
 
#if !defined(__FreeBSD__)
929
 
/*
930
 
 *----------------------------------------------------------------------
931
 
 *
932
 
 * HostinfoGetCpuInfo --
933
 
 *
934
 
 *      Get some attribute from /proc/cpuinfo for a given CPU
935
 
 *
936
 
 * Results:
937
 
 *      On success: Allocated, NUL-terminated attribute string.
938
 
 *      On failure: NULL.
939
 
 *
940
 
 * Side effects:
941
 
 *      None.
942
 
 *
943
 
 *----------------------------------------------------------------------
944
 
 */
945
 
 
946
 
char *
947
 
HostinfoGetCpuInfo(int nCpu,         // IN 
948
 
                   char *name)       // IN
949
 
{
950
 
   FILE *f;
951
 
   char *line;
952
 
   int cpu = 0;
953
 
   char *value = NULL;
954
 
 
955
 
   f = Posix_Fopen("/proc/cpuinfo", "r");
956
 
   if (f == NULL) { 
957
 
      Warning(LGPFX" HostinfoGetCpuInfo: Unable to open /proc/cpuinfo\n");
958
 
      return NULL;
959
 
   }
960
 
      
961
 
   while (cpu <= nCpu && 
962
 
          StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) {
963
 
      char *s;
964
 
      char *e;
965
 
 
966
 
      if ((s = strstr(line, name)) &&
967
 
          (s = strchr(s, ':'))) {
968
 
         s++;
969
 
         e = s + strlen(s);
970
 
 
971
 
         /* Skip leading and trailing while spaces */
972
 
         for (; s < e && isspace(*s); s++);
973
 
         for (; s < e && isspace(e[-1]); e--);
974
 
         *e = 0;
975
 
         
976
 
         /* Free previous value */
977
 
         free(value);
978
 
         value = strdup(s);
979
 
         ASSERT_MEM_ALLOC(value);
980
 
         
981
 
         cpu++;
982
 
      }
983
 
      free(line);
984
 
   }     
985
 
 
986
 
   fclose(f);
987
 
   return value; 
988
 
}
989
 
#endif /* __FreeBSD__ */
990
 
 
991
 
/*
992
 
 *----------------------------------------------------------------------
993
 
 *
994
 
 * HostinfoFindEntry --
995
 
 *
996
 
 *      Search a buffer for a pair `STRING <blanks> DIGITS'
997
 
 *      and return the number DIGITS, or 0 when fail.
998
 
 *
999
 
 * Results:
1000
 
 *      TRUE on  success, FALSE on failure
1001
 
 *
1002
 
 * Side effects:
1003
 
 *      None
1004
 
 *
1005
 
 *----------------------------------------------------------------------
1006
 
 */
1007
 
 
1008
 
static Bool 
1009
 
HostinfoFindEntry(char *buffer,         // IN: Buffer
1010
 
                  char *string,         // IN: String sought
1011
 
                  unsigned int *value)  // OUT: Value
1012
 
{
1013
 
   char *p = strstr(buffer, string);
1014
 
   unsigned int val;
1015
 
 
1016
 
   if (p == NULL) {
1017
 
      return FALSE;
1018
 
   }
1019
 
 
1020
 
   p += strlen(string);
1021
 
 
1022
 
   while (*p == ' ' || *p == '\t') {
1023
 
      p++;
1024
 
   }
1025
 
   if (*p < '0' || *p > '9') {
1026
 
      return FALSE;
1027
 
   }
1028
 
 
1029
 
   val = strtoul(p, NULL, 10);
1030
 
   if (errno == ERANGE || errno == EINVAL) {
1031
 
      return FALSE;
1032
 
   }
1033
 
 
1034
 
   *value = val;
1035
 
   return TRUE;
1036
 
}
1037
 
 
1038
 
 
1039
 
/*
1040
 
 *----------------------------------------------------------------------
1041
 
 *
1042
 
 * HostinfoGetMemInfo --
1043
 
 *
1044
 
 *      Get some attribute from /proc/meminfo
1045
 
 *      Return value is in KB.
1046
 
 *
1047
 
 * Results:
1048
 
 *      TRUE on success, FALSE on failure
1049
 
 *
1050
 
 * Side effects:
1051
 
 *      None.
1052
 
 *
1053
 
 *----------------------------------------------------------------------
1054
 
 */
1055
 
 
1056
 
Bool
1057
 
HostinfoGetMemInfo(char *name,          //IN
1058
 
                   unsigned int *value) //OUT
1059
 
{
1060
 
   size_t len;
1061
 
   char   buffer[4096];
1062
 
 
1063
 
   int fd = Posix_Open("/proc/meminfo", O_RDONLY);
1064
 
 
1065
 
   if (fd == -1) {
1066
 
      Warning(LGPFX" HostinfoGetMemInfo: Unable to open /proc/meminfo\n");
1067
 
      return FALSE;
1068
 
   }
1069
 
 
1070
 
   len = read(fd, buffer, sizeof buffer - 1);
1071
 
   close(fd);
1072
 
 
1073
 
   if (len == -1) {
1074
 
      return FALSE;
1075
 
   }
1076
 
 
1077
 
   buffer[len] = '\0';
1078
 
 
1079
 
   return HostinfoFindEntry(buffer, name, value);
1080
 
}
1081
 
 
1082
 
 
1083
 
/*
1084
 
 *-----------------------------------------------------------------------------
1085
 
 *
1086
 
 * HostinfoSysinfo --
1087
 
 *
1088
 
 *      Retrieve system information on a Linux system.
1089
 
 *    
1090
 
 * Results:
1091
 
 *      TRUE on success: '*totalRam', '*freeRam', '*totalSwap' and '*freeSwap'
1092
 
 *                       are set if not NULL
1093
 
 *      FALSE on failure
1094
 
 *
1095
 
 * Side effects:
1096
 
 *      None.
1097
 
 *
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
1101
 
 *
1102
 
 *-----------------------------------------------------------------------------
1103
 
 */
1104
 
 
1105
 
static Bool
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
1110
 
{
1111
 
#ifdef HAVE_SYSINFO
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)];
1129
 
   };
1130
 
   struct vmware_sysinfo si;
1131
 
 
1132
 
   if (sysinfo((struct sysinfo *)&si) < 0) {
1133
 
      return FALSE;
1134
 
   }
1135
 
   
1136
 
   if (si.mem_unit == 0) {
1137
 
      /*
1138
 
       * Kernel versions < 2.3.23. Those kernels used a smaller sysinfo
1139
 
       * structure, whose last meaningful field is 'procs' --hpreg
1140
 
       */
1141
 
      si.mem_unit = 1;
1142
 
   }
1143
 
 
1144
 
   if (totalRam) {
1145
 
      *totalRam = (uint64)si.totalram * si.mem_unit;
1146
 
   }
1147
 
   if (freeRam) {
1148
 
      *freeRam = (uint64)si.freeram * si.mem_unit;
1149
 
   }
1150
 
   if (totalSwap) {
1151
 
      *totalSwap = (uint64)si.totalswap * si.mem_unit;
1152
 
   }
1153
 
   if (freeSwap) {
1154
 
      *freeSwap = (uint64)si.freeswap * si.mem_unit;
1155
 
   }
1156
 
 
1157
 
   return TRUE;
1158
 
#else // ifdef HAVE_SYSINFO
1159
 
   NOT_IMPLEMENTED();
1160
 
#endif // ifdef HAVE_SYSINFO
1161
 
}
1162
 
#endif // ifndef __APPLE__
1163
 
 
1164
 
 
1165
 
#if defined(__linux__) || defined(__FreeBSD__) || defined(sun)
1166
 
/*
1167
 
 *-----------------------------------------------------------------------------
1168
 
 *
1169
 
 * HostinfoGetLinuxMemoryInfoInPages --
1170
 
 *
1171
 
 *      Obtain the minimum memory to be maintained, total memory available, and
1172
 
 *      free memory available on the host (Linux or COS) in pages.
1173
 
 *
1174
 
 * Results:
1175
 
 *      TRUE on success: '*minSize', '*maxSize' and '*currentSize' are set
1176
 
 *      FALSE on failure
1177
 
 *
1178
 
 * Side effects:
1179
 
 *      None
1180
 
 *
1181
 
 *-----------------------------------------------------------------------------
1182
 
 */
1183
 
 
1184
 
Bool
1185
 
HostinfoGetLinuxMemoryInfoInPages(unsigned int *minSize,     // OUT
1186
 
                                  unsigned int *maxSize,     // OUT
1187
 
                                  unsigned int *currentSize) // OUT
1188
 
{
1189
 
   uint64 total; 
1190
 
   uint64 free;
1191
 
   unsigned int cached = 0;
1192
 
   
1193
 
   /*
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
1199
 
    * kernel.
1200
 
    *
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.
1207
 
    */
1208
 
 
1209
 
   if (HostinfoSysinfo(&total, &free, NULL, NULL) == FALSE) {
1210
 
      return FALSE;
1211
 
   }
1212
 
 
1213
 
   /*
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.
1217
 
    */
1218
 
   if (total < (uint64)128 * 1024 * 1024) {
1219
 
      total = ROUNDUP(total, (uint64)8 * 1024 * 1024);
1220
 
   } else {
1221
 
      total = ROUNDUP(total, (uint64)32 * 1024 * 1024);
1222
 
   }
1223
 
 
1224
 
   *minSize = 128; // XXX - Figure out this value
1225
 
   *maxSize = total / PAGE_SIZE;
1226
 
 
1227
 
   HostinfoGetMemInfo("Cached:", &cached);
1228
 
   if (currentSize) {
1229
 
      *currentSize = free / PAGE_SIZE + cached / (PAGE_SIZE / 1024);
1230
 
   }
1231
 
 
1232
 
   return TRUE;
1233
 
}
1234
 
 
1235
 
 
1236
 
/*
1237
 
 *-----------------------------------------------------------------------------
1238
 
 *
1239
 
 * HostinfoGetSwapInfoInPages --
1240
 
 *
1241
 
 *      Obtain the total swap and free swap on the host (Linux or COS) in pages.
1242
 
 *
1243
 
 * Results:
1244
 
 *      TRUE on success: '*totalSwap' and '*freeSwap' are set if not NULL
1245
 
 *      FALSE on failure
1246
 
 *
1247
 
 * Side effects:
1248
 
 *      None
1249
 
 *
1250
 
 *-----------------------------------------------------------------------------
1251
 
 */
1252
 
 
1253
 
Bool
1254
 
Hostinfo_GetSwapInfoInPages(unsigned int *totalSwap,     // OUT
1255
 
                            unsigned int *freeSwap)      // OUT
1256
 
{
1257
 
   uint64 total; 
1258
 
   uint64 free;
1259
 
 
1260
 
   if (HostinfoSysinfo(NULL, NULL, &total, &free) == FALSE) {
1261
 
      return FALSE;
1262
 
   }
1263
 
 
1264
 
   if (totalSwap != NULL) {
1265
 
      *totalSwap = total / PAGE_SIZE;
1266
 
   }
1267
 
 
1268
 
   if (freeSwap != NULL) {
1269
 
      *freeSwap = free / PAGE_SIZE;
1270
 
   }
1271
 
 
1272
 
   return TRUE;
1273
 
}
1274
 
#endif
1275
 
 
1276
 
 
1277
 
/*
1278
 
 *-----------------------------------------------------------------------------
1279
 
 *
1280
 
 * Hostinfo_GetMemoryInfoInPages --
1281
 
 *
1282
 
 *      Obtain the minimum memory to be maintained, total memory available, and
1283
 
 *      free memory available on the host in pages.
1284
 
 *
1285
 
 * Results:
1286
 
 *      TRUE on success: '*minSize', '*maxSize' and '*currentSize' are set
1287
 
 *      FALSE on failure
1288
 
 *
1289
 
 * Side effects:
1290
 
 *      None
1291
 
 *
1292
 
 *-----------------------------------------------------------------------------
1293
 
 */
1294
 
 
1295
 
Bool
1296
 
Hostinfo_GetMemoryInfoInPages(unsigned int *minSize,     // OUT
1297
 
                              unsigned int *maxSize,     // OUT
1298
 
                              unsigned int *currentSize) // OUT
1299
 
{
1300
 
#if defined(__APPLE__)
1301
 
   mach_msg_type_number_t count;
1302
 
   vm_statistics_data_t stat;
1303
 
   kern_return_t error;
1304
 
   uint64_t memsize;
1305
 
   size_t memsizeSize = sizeof memsize;
1306
 
 
1307
 
   /*
1308
 
    * Largely inspired by
1309
 
    * darwinsource-10.4.5/top-15/libtop.c::libtop_p_vm_sample().
1310
 
    */
1311
 
 
1312
 
   count = HOST_VM_INFO_COUNT;
1313
 
   error = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&stat,
1314
 
                           &count);
1315
 
   if (error != KERN_SUCCESS || count != HOST_VM_INFO_COUNT) {
1316
 
      Warning("%s: Unable to retrieve host vm stats.\n", __FUNCTION__);
1317
 
      return FALSE;
1318
 
   }
1319
 
 
1320
 
   // XXX Figure out this value.
1321
 
   *minSize = 128;
1322
 
 
1323
 
   /*
1324
 
    * XXX Hopefully this includes cached memory as well. We should check.
1325
 
    * No. It returns only completely used pages.
1326
 
    */
1327
 
   *currentSize = stat.free_count;
1328
 
 
1329
 
   /*
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.
1332
 
    */
1333
 
   if (sysctlbyname("hw.memsize", &memsize, &memsizeSize, NULL, 0) == -1) {
1334
 
      Warning("%s: Unable to retrieve host vm hw.memsize.\n", __FUNCTION__);
1335
 
      return FALSE;
1336
 
   }
1337
 
 
1338
 
   *maxSize = memsize / PAGE_SIZE;
1339
 
   return TRUE;
1340
 
#elif defined(VMX86_SERVER)
1341
 
   uint64 total; 
1342
 
   uint64 free;
1343
 
   VMK_ReturnStatus status;
1344
 
 
1345
 
   if (VmkSyscall_Init(FALSE, NULL, 0)) {
1346
 
      status = CosVmnix_GetMemSize(&total, &free);
1347
 
      if (status == VMK_OK) {
1348
 
         *minSize = 128;
1349
 
         *maxSize = total / PAGE_SIZE;
1350
 
         *currentSize = free / PAGE_SIZE;
1351
 
 
1352
 
         return TRUE;
1353
 
      }
1354
 
   }
1355
 
 
1356
 
   return FALSE;
1357
 
#else
1358
 
   return HostinfoGetLinuxMemoryInfoInPages(minSize, maxSize, currentSize);
1359
 
#endif
1360
 
}
1361
 
 
1362
 
 
1363
 
#ifdef VMX86_SERVER
1364
 
/*
1365
 
 *-----------------------------------------------------------------------------
1366
 
 *
1367
 
 * Hostinfo_GetCOSMemoryInfoInPages --
1368
 
 *
1369
 
 *      Obtain the minimum memory to be maintained, total memory available, and
1370
 
 *      free memory available on the COS in pages.
1371
 
 *
1372
 
 * Results:
1373
 
 *      TRUE on success: '*minSize', '*maxSize' and '*currentSize' are set
1374
 
 *      FALSE on failure
1375
 
 *
1376
 
 * Side effects:
1377
 
 *      None
1378
 
 *
1379
 
 *-----------------------------------------------------------------------------
1380
 
 */
1381
 
 
1382
 
Bool
1383
 
Hostinfo_GetCOSMemoryInfoInPages(unsigned int *minSize,     // OUT
1384
 
                                 unsigned int *maxSize,     // OUT
1385
 
                                 unsigned int *currentSize) // OUT
1386
 
{
1387
 
   if (HostType_OSIsPureVMK()) {
1388
 
      return FALSE;
1389
 
   } else {
1390
 
      return HostinfoGetLinuxMemoryInfoInPages(minSize, maxSize, currentSize);
1391
 
   }
1392
 
}
1393
 
#endif
1394
 
 
1395
 
 
1396
 
/*
1397
 
 *----------------------------------------------------------------------
1398
 
 *
1399
 
 * Hostinfo_ResetProcessState --
1400
 
 *
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.
1403
 
 *
1404
 
 * Results:
1405
 
 *      None.
1406
 
 *
1407
 
 * Side effects:
1408
 
 *      None.
1409
 
 *
1410
 
 *----------------------------------------------------------------------
1411
 
 */
1412
 
void
1413
 
Hostinfo_ResetProcessState(const int *keepFds, // IN:
1414
 
                           size_t numKeepFds)  // IN:
1415
 
{
1416
 
   int s, fd;
1417
 
   struct sigaction sa;
1418
 
   struct rlimit rlim;
1419
 
#ifdef __linux__
1420
 
   int err;
1421
 
   uid_t euid;
1422
 
#endif
1423
 
 
1424
 
   /*
1425
 
    * Disable itimers before resetting the signal handlers.
1426
 
    * Otherwise, the process may still receive timer signals:
1427
 
    * SIGALRM, SIGVTARLM, or SIGPROF.
1428
 
    */
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);
1435
 
 
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);
1441
 
   }
1442
 
   for (fd = (int) sysconf(_SC_OPEN_MAX) - 1; fd > STDERR_FILENO; fd--) {
1443
 
      size_t i;
1444
 
      for (i = 0; i < numKeepFds; i++) {
1445
 
         if (fd == keepFds[i]) {
1446
 
            break;
1447
 
         }
1448
 
      }
1449
 
      if (i == numKeepFds) {
1450
 
         (void) close(fd);
1451
 
      }
1452
 
   }
1453
 
 
1454
 
   if (getrlimit(RLIMIT_AS, &rlim) == 0) {
1455
 
      rlim.rlim_cur = rlim.rlim_max;
1456
 
      setrlimit(RLIMIT_AS, &rlim);
1457
 
   }
1458
 
 
1459
 
#ifdef __linux__
1460
 
   /*
1461
 
    * Drop iopl to its default value.
1462
 
    */
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);
1467
 
   Id_SetEUid(0);
1468
 
   err = iopl(0);
1469
 
   Id_SetEUid(euid);
1470
 
   ASSERT_NOT_IMPLEMENTED(err == 0);
1471
 
#endif
1472
 
}
1473
 
 
1474
 
 
1475
 
/*
1476
 
 *----------------------------------------------------------------------
1477
 
 *
1478
 
 * Hostinfo_Execute --
1479
 
 *
1480
 
 *      Start program COMMAND.  If WAIT is TRUE, wait for program
1481
 
 *      to complete and return exit status.
1482
 
 *
1483
 
 * Results:
1484
 
 *      Exit status of COMMAND.
1485
 
 *
1486
 
 * Side effects:
1487
 
 *      Run a separate program.
1488
 
 *
1489
 
 *----------------------------------------------------------------------
1490
 
 */
1491
 
int
1492
 
Hostinfo_Execute(const char *command,
1493
 
                 char * const *args,
1494
 
                 Bool wait)
1495
 
{
1496
 
   int pid;
1497
 
   int status;
1498
 
 
1499
 
   if (command == NULL) {
1500
 
      return 1;
1501
 
   }
1502
 
 
1503
 
   pid = fork();
1504
 
 
1505
 
   if (pid == -1) {
1506
 
      return -1;
1507
 
   }
1508
 
 
1509
 
   if (pid == 0) {
1510
 
      Hostinfo_ResetProcessState(NULL, 0);
1511
 
      Posix_Execvp(command, args);
1512
 
      exit(127);
1513
 
   }
1514
 
 
1515
 
   if (wait) {
1516
 
      for (;;) {
1517
 
         if (waitpid(pid, &status, 0) == -1) {
1518
 
            if (errno == ECHILD) {
1519
 
               return 0;        // This sucks.  We really don't know.
1520
 
            }
1521
 
            if (errno != EINTR) {
1522
 
               return -1;
1523
 
            }
1524
 
         } else {
1525
 
            return status;
1526
 
         }
1527
 
      }
1528
 
   } else {
1529
 
      return 0;
1530
 
   }
1531
 
}
1532
 
 
1533
 
 
1534
 
/*
1535
 
 *-----------------------------------------------------------------------------
1536
 
 *
1537
 
 * Hostinfo_Daemonize --
1538
 
 *
1539
 
 *      Cross-platform daemon(3)-like wrapper.
1540
 
 *
1541
 
 *      Restarts the current process as a daemon, given the path to the
1542
 
 *      process (usually from Hostinfo_GetModulePath).  This means:
1543
 
 *
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
1547
 
 *           process group.
1548
 
 *         * Your stdin/stdout/stderr fds are redirected to /dev/null.
1549
 
 *         * Your main() function is called with the specified NULL-terminated
1550
 
 *           argument list.
1551
 
 *
1552
 
 *      (Don't forget that the first string in args is argv[0] -- the
1553
 
 *      name of the process).
1554
 
 *
1555
 
 *      Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCHDIR, then the
1556
 
 *      current directory of the daemon process is set to "/".
1557
 
 *
1558
 
 *      Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCLOSE, then all stdio
1559
 
 *      file descriptors of the daemon process are redirected to /dev/null.
1560
 
 *
1561
 
 *      If 'flags' contains HOSTINFO_DAEMONIZE_EXIT, then upon successful
1562
 
 *      launch of the daemon, the original process will exit.
1563
 
 *
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.
1567
 
 *
1568
 
 * Results:
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.
1575
 
 *
1576
 
 * Side effects:
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).
1580
 
 *
1581
 
 *-----------------------------------------------------------------------------
1582
 
 */
1583
 
 
1584
 
Bool
1585
 
Hostinfo_Daemonize(const char *path,             // IN: NUL-terminated UTF-8
1586
 
                                                 // path to exec
1587
 
                   char * const *args,           // IN: NULL-terminated UTF-8
1588
 
                                                 // argv list
1589
 
                   HostinfoDaemonizeFlags flags, // IN: flags
1590
 
                   const char *pidPath)          // IN/OPT: NUL-terminated
1591
 
                                                 // UTF-8 path to write PID
1592
 
{
1593
 
   /*
1594
 
    * We use the double-fork method to make a background process whose
1595
 
    * parent is init instead of the original process.
1596
 
    *
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
1599
 
    * warning.
1600
 
    *
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.
1605
 
    */
1606
 
   int childPid;
1607
 
   int pipeFds[2] = { -1, -1 };
1608
 
   uint32 err = EINVAL;
1609
 
   char *pathLocalEncoding = NULL;
1610
 
   char *pidPathLocalEncoding = NULL;
1611
 
   char **argsLocalEncoding = NULL;
1612
 
 
1613
 
   ASSERT_ON_COMPILE(sizeof (errno) <= sizeof err);
1614
 
 
1615
 
   if (pipe(pipeFds) == -1) {
1616
 
      err = Err_Errno();
1617
 
      Warning("%s: Couldn't create pipe, error %u.\n",
1618
 
              __FUNCTION__, err);
1619
 
      goto cleanup;
1620
 
   }
1621
 
 
1622
 
   if (fcntl(F_SETFD, pipeFds[1], 1) == -1) {
1623
 
      err = Err_Errno();
1624
 
      Warning("%s: Couldn't set close-on-exec for fd %d, error %u.\n",
1625
 
              __FUNCTION__, pipeFds[1], err);
1626
 
      goto cleanup;
1627
 
   }
1628
 
 
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);
1634
 
      goto cleanup;
1635
 
   }
1636
 
 
1637
 
   if (pidPath) {
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);
1643
 
         goto cleanup;
1644
 
      }
1645
 
   }
1646
 
 
1647
 
   argsLocalEncoding = Unicode_GetAllocList(args, STRING_ENCODING_DEFAULT, -1);
1648
 
   if (!argsLocalEncoding) {
1649
 
      Warning("%s: Couldn't convert arguments to default encoding.\n",
1650
 
              __FUNCTION__);
1651
 
      goto cleanup;
1652
 
   }
1653
 
 
1654
 
   childPid = fork();
1655
 
 
1656
 
   switch (childPid) {
1657
 
   case -1:
1658
 
      err = Err_Errno();
1659
 
      Warning("%s: Couldn't fork first child, error %u.\n",
1660
 
              __FUNCTION__, err);
1661
 
      goto cleanup;
1662
 
   case 0:
1663
 
      // We're the first child.  Continue on.
1664
 
      break;
1665
 
   default:
1666
 
      {
1667
 
         // We're the original process.  Check if the first child exited.
1668
 
         int status;
1669
 
         FileIODescriptor pipeDesc;
1670
 
 
1671
 
         close(pipeFds[1]);
1672
 
 
1673
 
         pipeDesc = FileIO_CreateFDPosix(pipeFds[0], O_RDONLY);
1674
 
 
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));
1679
 
            goto cleanup;
1680
 
         } else if (WIFSIGNALED(status)) {
1681
 
            Warning("%s: Child %d exited with signal %d.\n",
1682
 
                    __FUNCTION__, childPid, WTERMSIG(status));
1683
 
            goto cleanup;
1684
 
         }
1685
 
 
1686
 
         /*
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.
1691
 
          */
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);
1695
 
            goto cleanup;
1696
 
         }
1697
 
 
1698
 
         err = 0;
1699
 
         goto cleanup;
1700
 
      }
1701
 
   }
1702
 
 
1703
 
   /*
1704
 
    * Close all fds except for the write end of the error pipe (which
1705
 
    * we've already set to close on successful exec).
1706
 
    */
1707
 
   Hostinfo_ResetProcessState(&pipeFds[1], 1);
1708
 
 
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);
1713
 
   }
1714
 
 
1715
 
   switch (fork()) {
1716
 
   case -1:
1717
 
      {
1718
 
         Warning("%s: Couldn't fork second child, error %d.\n",
1719
 
                 __FUNCTION__, Err_Errno());
1720
 
         _exit(EXIT_FAILURE);
1721
 
      }
1722
 
   case 0:
1723
 
      // We're the second child.  Continue on.
1724
 
      break;
1725
 
   default:
1726
 
      /*
1727
 
       * We're the first child.  We don't need to exist any more.
1728
 
       *
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.
1732
 
       */
1733
 
      _exit(EXIT_SUCCESS);
1734
 
   }
1735
 
 
1736
 
   /*
1737
 
    * We can't use our i18n wrappers for file manipulation at this
1738
 
    * point, since we've forked; internal library mutexes might be
1739
 
    * invalid.
1740
 
    */
1741
 
   if (!(flags & HOSTINFO_DAEMONIZE_NOCHDIR) && chdir("/") == -1) {
1742
 
      uint32 err = Err_Errno();
1743
 
      Warning("%s: Couldn't chdir to /, error %u.\n",
1744
 
              __FUNCTION__, err);
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",
1748
 
                 Err_Errno(), err);
1749
 
      }
1750
 
      _exit(EXIT_FAILURE);
1751
 
   }
1752
 
 
1753
 
   if (!(flags & HOSTINFO_DAEMONIZE_NOCLOSE)) {
1754
 
      int fd;
1755
 
 
1756
 
      fd = open(_PATH_DEVNULL, O_RDONLY);
1757
 
      if (fd != -1) {
1758
 
         dup2(fd, STDIN_FILENO);
1759
 
         close(fd);
1760
 
      }
1761
 
 
1762
 
      fd = open(_PATH_DEVNULL, O_WRONLY);
1763
 
      if (fd != -1) {
1764
 
         dup2(fd, STDOUT_FILENO);
1765
 
         dup2(fd, STDERR_FILENO);
1766
 
         close(fd);
1767
 
      }
1768
 
   }
1769
 
 
1770
 
   if (pidPath) {
1771
 
      int64 pid;
1772
 
      char pidString[32];
1773
 
      int pidStringLen;
1774
 
      int pidPathFd;
1775
 
      FileIODescriptor pidDesc;
1776
 
 
1777
 
      ASSERT_ON_COMPILE(sizeof (pid_t) <= sizeof pid);
1778
 
      ASSERT(pidPathLocalEncoding);
1779
 
 
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);
1782
 
 
1783
 
      if (pidPathFd == -1) {
1784
 
         err = Err_Errno();
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",
1789
 
                    Err_Errno(), err);
1790
 
         }
1791
 
         _exit(EXIT_FAILURE);
1792
 
      }
1793
 
 
1794
 
      pid = getpid();
1795
 
      pidStringLen = Str_Sprintf(pidString, sizeof pidString,
1796
 
                                 "%"FMT64"d\n", pid);
1797
 
      if (pidStringLen <= 0) {
1798
 
         err = EINVAL;
1799
 
         if (write(pipeFds[1], &err, sizeof err) == -1) {
1800
 
            Warning("Couldn't write to parent pipe: %u, original error: %u.\n",
1801
 
                    Err_Errno(), err);
1802
 
         }
1803
 
         _exit(EXIT_FAILURE);
1804
 
      }
1805
 
 
1806
 
      pidDesc = FileIO_CreateFDPosix(pidPathFd, O_WRONLY);
1807
 
 
1808
 
      if (FileIO_Write(&pidDesc, pidString, pidStringLen, NULL) !=
1809
 
          FILEIO_SUCCESS) {
1810
 
         err = Err_Errno();
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",
1815
 
                    Err_Errno(), err);
1816
 
         }
1817
 
         _exit(EXIT_FAILURE);
1818
 
      }
1819
 
 
1820
 
      close(pidPathFd);
1821
 
   }
1822
 
 
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",
1830
 
                 Err_Errno(), err);
1831
 
      }
1832
 
      _exit(EXIT_FAILURE);
1833
 
   }
1834
 
 
1835
 
   NOT_REACHED();
1836
 
 
1837
 
  cleanup:
1838
 
   if (pipeFds[0] != -1) {
1839
 
      close(pipeFds[0]);
1840
 
   }
1841
 
   if (pipeFds[1] != -1) {
1842
 
      close(pipeFds[1]);
1843
 
   }
1844
 
   Util_FreeStringList(argsLocalEncoding, -1);
1845
 
   free(pidPathLocalEncoding);
1846
 
   free(pathLocalEncoding);
1847
 
 
1848
 
   if (err == 0) {
1849
 
      if (flags & HOSTINFO_DAEMONIZE_EXIT) {
1850
 
         _exit(EXIT_SUCCESS);
1851
 
      }
1852
 
   } else {
1853
 
      Err_SetErrno(err);
1854
 
 
1855
 
      if (pidPath) {
1856
 
         File_Unlink(pidPath);
1857
 
      }
1858
 
   }
1859
 
 
1860
 
   return (err == 0);
1861
 
}
1862
 
 
1863
 
 
1864
 
/*
1865
 
 *----------------------------------------------------------------------
1866
 
 *
1867
 
 * Hostinfo_OSIsSMP --
1868
 
 *
1869
 
 *      Host OS SMP capability.
1870
 
 *
1871
 
 * Results:
1872
 
 *      TRUE is host OS is SMP capable.
1873
 
 *
1874
 
 * Side effects:
1875
 
 *      None.
1876
 
 *
1877
 
 *----------------------------------------------------------------------
1878
 
 */
1879
 
 
1880
 
Bool
1881
 
Hostinfo_OSIsSMP(void)
1882
 
{
1883
 
   uint32 ncpu;
1884
 
 
1885
 
#if defined(__APPLE__)
1886
 
   size_t ncpuSize = sizeof ncpu;
1887
 
 
1888
 
   if (sysctlbyname("hw.ncpu", &ncpu, &ncpuSize, NULL, 0) == -1) {
1889
 
      return FALSE;
1890
 
   }
1891
 
 
1892
 
#else
1893
 
   ncpu = Hostinfo_NumCPUs();
1894
 
 
1895
 
   if (ncpu == 0xFFFFFFFF) {
1896
 
      return FALSE;
1897
 
   }
1898
 
#endif
1899
 
 
1900
 
   return ncpu > 1 ? TRUE : FALSE;
1901
 
}
1902
 
 
1903
 
/*
1904
 
 *-----------------------------------------------------------------------------
1905
 
 *
1906
 
 * Hostinfo_GetModulePath --
1907
 
 *
1908
 
 *      Retrieve the full path to the executable. Not supported under VMvisor.
1909
 
 *
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).
1913
 
 *
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.
1917
 
 *
1918
 
 * Results:
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.
1922
 
 *
1923
 
 *      On failure: NULL.
1924
 
 *
1925
 
 * Side effects:
1926
 
 *      None
1927
 
 *
1928
 
 *-----------------------------------------------------------------------------
1929
 
 */
1930
 
 
1931
 
Unicode
1932
 
Hostinfo_GetModulePath(uint32 priv)
1933
 
{
1934
 
   Unicode path;
1935
 
 
1936
 
#if defined(__APPLE__)
1937
 
   uint32_t pathSize = FILE_MAXPATH;
1938
 
#else
1939
 
   uid_t uid = -1;
1940
 
#endif
1941
 
 
1942
 
   if ((priv != HGMP_PRIVILEGE) && (priv != HGMP_NO_PRIVILEGE)) {
1943
 
      Warning("%s: invalid privilege parameter\n", __FUNCTION__);
1944
 
      return NULL;
1945
 
   }
1946
 
 
1947
 
#if defined(__APPLE__)
1948
 
   path = Util_SafeMalloc(pathSize);
1949
 
   if (_NSGetExecutablePath(path, &pathSize)) {
1950
 
      Warning(LGPFX" %s: _NSGetExecutablePath failed.\n", __FUNCTION__);
1951
 
      free(path);
1952
 
      return NULL;
1953
 
   }
1954
 
 
1955
 
#else
1956
 
#if defined(VMX86_SERVER)
1957
 
   if (HostType_OSIsVMK()) {
1958
 
      return NULL;
1959
 
   }
1960
 
#endif
1961
 
 
1962
 
   // "/proc/self/exe" only exists on Linux 2.2+.
1963
 
   ASSERT(Hostinfo_OSVersion(0) >= 2 && Hostinfo_OSVersion(1) >= 2);
1964
 
 
1965
 
   if (priv == HGMP_PRIVILEGE) {
1966
 
      uid = Id_BeginSuperUser();
1967
 
   }
1968
 
 
1969
 
   path = Posix_ReadLink("/proc/self/exe");
1970
 
 
1971
 
   if (priv == HGMP_PRIVILEGE) {
1972
 
      Id_EndSuperUser(uid);
1973
 
   }
1974
 
 
1975
 
   if (path == NULL) {
1976
 
      Warning(LGPFX" %s: readlink failed: %s\n",
1977
 
              __FUNCTION__, Err_ErrString());
1978
 
   }
1979
 
#endif
1980
 
 
1981
 
   return path;
1982
 
}
1983
 
 
1984
 
 
1985
 
/*
1986
 
 *----------------------------------------------------------------------
1987
 
 *
1988
 
 *  Hostinfo_TouchBackDoor --
1989
 
 *
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.
1998
 
 *
1999
 
 * Results:
2000
 
 *      TRUE if we succesfully accessed the backdoor, FALSE or segfault
2001
 
 *      if not.
2002
 
 *
2003
 
 * Side effects:
2004
 
 *      Exception if not in a VM. 
2005
 
 *
2006
 
 *----------------------------------------------------------------------
2007
 
 */
2008
 
 
2009
 
Bool
2010
 
Hostinfo_TouchBackDoor(void)
2011
 
{
2012
 
   /*
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
2015
 
    * it.
2016
 
    *
2017
 
    * It's also annoying in gdb, so we'll turn it off in devel builds.
2018
 
    */
2019
 
#if !defined(__APPLE__) && !defined(VMX86_DEVEL)
2020
 
   uint32 eax;
2021
 
   uint32 ebx;
2022
 
   uint32 ecx;
2023
 
 
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"
2028
 
      "xchgl %%ebx, %1"
2029
 
      : "=a" (eax),
2030
 
        "=&rm" (ebx),
2031
 
#   else
2032
 
      "inl %%dx, %%eax"
2033
 
      : "=a" (eax),
2034
 
        "=b" (ebx),
2035
 
#   endif
2036
 
        "=c" (ecx)
2037
 
      : "0" (BDOOR_MAGIC),
2038
 
        "1" (~BDOOR_MAGIC),
2039
 
        "2" (BDOOR_CMD_GETVERSION),
2040
 
        "d" (BDOOR_PORT)
2041
 
   );
2042
 
   if (ebx == BDOOR_MAGIC) {
2043
 
      return TRUE;
2044
 
   }
2045
 
#endif
2046
 
   return FALSE;
2047
 
}
2048
 
 
2049
 
 
2050
 
/*
2051
 
 *-----------------------------------------------------------------------------
2052
 
 *
2053
 
 * Hostinfo_GetUser --
2054
 
 *
2055
 
 *      Return current user name, or NULL if can't tell.
2056
 
 *      XXX Not thread-safe (somebody could do a setenv()). --hpreg
2057
 
 *
2058
 
 * Results:
2059
 
 *      User name.  Must be free()d by caller.
2060
 
 *
2061
 
 * Side effects:
2062
 
 *      No.
2063
 
 *
2064
 
 *-----------------------------------------------------------------------------
2065
 
 */
2066
 
 
2067
 
Unicode
2068
 
Hostinfo_GetUser()
2069
 
{
2070
 
   char buffer[BUFSIZ];
2071
 
   struct passwd pw;
2072
 
   struct passwd *ppw = &pw;
2073
 
   Unicode env = NULL;
2074
 
   Unicode name = NULL;
2075
 
 
2076
 
   if ((Posix_Getpwuid_r(getuid(), &pw, buffer, sizeof buffer, &ppw) == 0) &&
2077
 
       (ppw != NULL)) {
2078
 
      if (ppw->pw_name) {
2079
 
         name = Unicode_Duplicate(ppw->pw_name);
2080
 
      }
2081
 
   }
2082
 
 
2083
 
   if (!name) {
2084
 
      env = Posix_Getenv("USER");
2085
 
      if (env) {
2086
 
         name = Unicode_Duplicate(env);
2087
 
      }
2088
 
   }
2089
 
   return name;
2090
 
}
2091
 
 
2092
 
/*
2093
 
 *-----------------------------------------------------------------------------
2094
 
 *
2095
 
 * Hostinfo_LogMemUsage --
2096
 
 *      Log system memory usage.
2097
 
 *
2098
 
 * Results:
2099
 
 *      System memory usage is logged.
2100
 
 *
2101
 
 * Side effects:
2102
 
 *      No.
2103
 
 *
2104
 
 *-----------------------------------------------------------------------------
2105
 
 */
2106
 
 
2107
 
void
2108
 
Hostinfo_LogMemUsage(void)
2109
 
{
2110
 
   int fd = Posix_Open("/proc/self/statm", O_RDONLY);
2111
 
 
2112
 
   if (fd != -1) {
2113
 
      size_t len;
2114
 
      char buf[64];
2115
 
 
2116
 
      len = read(fd, buf, sizeof buf);
2117
 
      close(fd);
2118
 
 
2119
 
      if (len != -1) {
2120
 
         int a[7] = { 0 };
2121
 
 
2122
 
         buf[len < sizeof buf ? len : sizeof buf - 1] = '\0';
2123
 
 
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]);
2126
 
 
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]);
2129
 
      }
2130
 
   }
2131
 
}