~n-muench/ubuntu/oneiric/open-vm-tools/open-vm-tools.fix-836277

« back to all changes in this revision

Viewing changes to lib/user/utilPosix.c

  • Committer: Evan Broder
  • Date: 2010-03-21 23:26:53 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: broder@mit.edu-20100321232653-5a57r7v7ch4o6byv
Merging shared upstream rev into target branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*********************************************************
2
 
 * Copyright (C) 2004 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
 
 * utilPosix.c --
21
 
 *
22
 
 *      Posix misc util functions.
23
 
 */
24
 
 
25
 
#include <string.h>
26
 
#include <sys/stat.h>
27
 
#include <sys/param.h>
28
 
#include <sys/types.h>
29
 
#include <sys/stat.h>
30
 
#include <sys/ioctl.h>
31
 
#include <sys/time.h>
32
 
#include <sys/resource.h>
33
 
#include <fcntl.h>
34
 
#include <unistd.h>
35
 
#include <errno.h>
36
 
#include <dirent.h>
37
 
#include <ctype.h>
38
 
 
39
 
#if !__FreeBSD__ && !sun
40
 
#   include <pwd.h>
41
 
#endif
42
 
 
43
 
#ifdef sun
44
 
#   include <procfs.h>
45
 
#endif
46
 
 
47
 
#include "vmware.h"
48
 
#include "file.h"
49
 
#include "util.h"
50
 
#include "su.h"
51
 
#include "vm_atomic.h"
52
 
#include "str.h"
53
 
#include "vm_version.h"
54
 
#include "random.h"
55
 
#include "hostinfo.h"
56
 
#include "syncMutex.h"
57
 
#include "escape.h"
58
 
#include "unicodeOperations.h"
59
 
#include "err.h"
60
 
#include "posix.h"
61
 
#include "vmstdio.h"
62
 
 
63
 
#define LOGLEVEL_MODULE util
64
 
#include "loglevel_user.h"
65
 
#define LGPFX "UtilPosix:"
66
 
 
67
 
 
68
 
/* For Util_GetProcessName() */
69
 
#ifdef sun
70
 
#   define PROCFILE  "psinfo"
71
 
#else
72
 
#   define PROCFILE  "status"
73
 
    /*
74
 
     * Note that the limit of what is output for the process name in
75
 
     * /proc/<pid>/status is 15 characters (30 with '\' -> '\\' escaping) on
76
 
     * Linux, and 19 characters (76 with ' ' -> '\040' escaping) on FreeBSD.
77
 
     * Reading in at most 128 gives us a bit of extra room in case these fields
78
 
     * grow in the future.  The 129 in our buffer is for the NUL terminator.
79
 
     */
80
 
#   define PSINFOSZ  129
81
 
#   ifdef __linux__
82
 
#      define PRE  "Name:   "
83
 
#      define POST "\n"
84
 
#      define PSINFOFMT "%128[^\n]"
85
 
#   else /* FreeBSD */
86
 
#      define PRE
87
 
#      define POST " "
88
 
#      define PSINFOFMT "%128s"
89
 
#   endif
90
 
#endif
91
 
 
92
 
#if defined(VMX86_STATS) && defined(__linux__) && !defined(VMX86_SERVER)
93
 
#define SYS_CSTATE_DIR  "/sys/devices/system/cpu"
94
 
#define PROC_CSTATE_DIR "/proc/acpi/processor"
95
 
#define MAX_C_STATES    8
96
 
#define FREQ_ACPI       3.579545
97
 
#endif
98
 
 
99
 
 
100
 
#if !__FreeBSD__ && !sun
101
 
 
102
 
/*
103
 
 *-----------------------------------------------------------------------------
104
 
 *
105
 
 * Util_BumpNoFds --
106
 
 *
107
 
 *      Bump the number of file descriptor this process can open to 2048. On
108
 
 *      failure sets *cur to the number of fds we can currently open, and sets
109
 
 *      *wanted to what we want.
110
 
 *
111
 
 * Results:
112
 
 *      0 on success, errno from the failing call to setrlimit(2) otherwise.
113
 
 *
114
 
 * Side effects:
115
 
 *      None
116
 
 *
117
 
 *-----------------------------------------------------------------------------
118
 
 */
119
 
 
120
 
int
121
 
Util_BumpNoFds(uint32 *cur,     // OUT
122
 
               uint32 *wanted)  // OUT
123
 
{
124
 
   struct rlimit lim;
125
 
   int err;
126
 
 
127
 
   /*
128
 
    * Check for minimum file descriptor limit. The number is
129
 
    * somewhat arbitrary. Trying to do multiple snapshots of a split
130
 
    * disk can rapidly consume descriptors however, so we ought to
131
 
    * have a large number. This is only pushing back the problem of
132
 
    * course. Ideally we'd have a fully scalable solution.
133
 
    */
134
 
 
135
 
#if __APPLE__
136
 
   static const rlim_t fdsDesired = 8192;
137
 
#else
138
 
   static const rlim_t fdsDesired = 2048;
139
 
#endif
140
 
 
141
 
   err = getrlimit(RLIMIT_NOFILE, &lim);
142
 
   ASSERT_NOT_IMPLEMENTED(err >= 0);
143
 
 
144
 
   if (cur) {
145
 
      *cur = lim.rlim_cur;
146
 
   }
147
 
   if (wanted) {
148
 
      *wanted = fdsDesired;
149
 
   }
150
 
 
151
 
   if (lim.rlim_cur != RLIM_INFINITY && lim.rlim_cur < fdsDesired) {
152
 
      Bool needSu;
153
 
 
154
 
      /*
155
 
       * First attempt to raise limit ourselves.
156
 
       * If that fails, complain and make user do it.
157
 
       */
158
 
 
159
 
      rlim_t curFdLimit = lim.rlim_cur;
160
 
      rlim_t maxFdLimit = lim.rlim_max;
161
 
 
162
 
      lim.rlim_cur = fdsDesired;
163
 
 
164
 
      /*
165
 
       * rlim_max may need to be increased as well.
166
 
       */
167
 
 
168
 
      needSu = lim.rlim_max != RLIM_INFINITY && lim.rlim_max < fdsDesired;
169
 
 
170
 
      if (needSu) {
171
 
         lim.rlim_max = fdsDesired;
172
 
      } else { 
173
 
         err = setrlimit(RLIMIT_NOFILE, &lim) < 0 ? errno : 0;
174
 
      }
175
 
 
176
 
      /*
177
 
       * Set euid to root for the FD limit increase. Note we don't need root
178
 
       * unless rlim_max is being increased.  Revert to non-root immediately
179
 
       * after.
180
 
       */
181
 
 
182
 
      if (err == EPERM || needSu) {
183
 
         uid_t uid = Id_BeginSuperUser();
184
 
 
185
 
         err = setrlimit(RLIMIT_NOFILE, &lim) < 0 ? errno : 0;
186
 
         Id_EndSuperUser(uid);
187
 
      }
188
 
 
189
 
      /*
190
 
       * If everything else failed, simply try using rlim_max. That might be
191
 
       * enough..
192
 
       */
193
 
 
194
 
      if (err != 0) {
195
 
         lim.rlim_cur = maxFdLimit;
196
 
         lim.rlim_max = maxFdLimit;
197
 
         err = setrlimit(RLIMIT_NOFILE, &lim) < 0 ? errno : 0;
198
 
         ASSERT_NOT_TESTED(err == 0);
199
 
      }
200
 
 
201
 
      if (err != 0) {
202
 
         Log("UTIL: Failed to set number of fds at %u, was %u: %s (%d)\n",
203
 
             (uint32)fdsDesired, (uint32)curFdLimit, Err_Errno2String(err),
204
 
             err); 
205
 
      }
206
 
   }
207
 
 
208
 
   return err;
209
 
}
210
 
 
211
 
 
212
 
/*
213
 
 *-----------------------------------------------------------------------------
214
 
 *
215
 
 * UtilGetUserName --
216
 
 *
217
 
 *      Retrieve the name associated with a user ID. Thread-safe
218
 
 *      version. --hpreg
219
 
 *
220
 
 * Results:
221
 
 *      The allocated name on success
222
 
 *      NULL on failure
223
 
 *
224
 
 * Side effects:
225
 
 *      None
226
 
 *
227
 
 *-----------------------------------------------------------------------------
228
 
 */
229
 
 
230
 
static char *
231
 
UtilGetUserName(uid_t uid) // IN
232
 
{
233
 
   long memPoolSize;
234
 
   char *memPool;
235
 
   struct passwd pw;
236
 
   struct passwd *pw_p;
237
 
   char *userName;
238
 
 
239
 
#if __APPLE__
240
 
   memPoolSize = _PASSWORD_LEN;
241
 
#else
242
 
   memPoolSize = sysconf(_SC_GETPW_R_SIZE_MAX);
243
 
   if (memPoolSize <= 0) {
244
 
      Warning("%s: sysconf(_SC_GETPW_R_SIZE_MAX) failed.\n", __FUNCTION__);
245
 
 
246
 
      return NULL;
247
 
   }
248
 
#endif
249
 
 
250
 
   memPool = malloc(memPoolSize);
251
 
   if (memPool == NULL) {
252
 
      Warning("%s: Not enough memory.\n", __FUNCTION__);
253
 
 
254
 
      return NULL;
255
 
   }
256
 
 
257
 
   if (Posix_Getpwuid_r(uid, &pw, memPool, memPoolSize, &pw_p) != 0) {
258
 
      free(memPool);
259
 
      Warning("%s: Unable to retrieve the username associated with "
260
 
              "user ID %u.\n", __FUNCTION__, uid);
261
 
 
262
 
      return NULL;
263
 
   }
264
 
 
265
 
   userName = strdup(pw_p->pw_name);
266
 
   free(memPool);
267
 
   if (userName == NULL) {
268
 
      Warning("%s: Not enough memory.\n", __FUNCTION__);
269
 
 
270
 
      return NULL;
271
 
   }
272
 
 
273
 
   return userName;
274
 
}
275
 
 
276
 
 
277
 
/*
278
 
 *----------------------------------------------------------------------
279
 
 *
280
 
 *  Util_MakeSafeTemp --
281
 
 *
282
 
 *      Exactly the same as File_MakeTemp except uses a safe directory
283
 
 *      as the default temporary directory.
284
 
 *
285
 
 *      This code is duplicated in identical form between utilPosix.c
286
 
 *      and utilWin32.c, but can't go in util.c because it depends on
287
 
 *      Util_GetSafeTmpDir whose Win32 implementation implies extra
288
 
 *      dependencies that some people who link just to util.c can't
289
 
 *      stomach.
290
 
 *
291
 
 * Results:
292
 
 *      Open file descriptor or -1
293
 
 *
294
 
 * Side effects:
295
 
 *      Creates a file if successful.
296
 
 *----------------------------------------------------------------------
297
 
 */
298
 
 
299
 
int
300
 
Util_MakeSafeTemp(ConstUnicode tag,  // IN (OPT):
301
 
                  Unicode *presult)  // OUT:
302
 
{
303
 
   int fd = -1;
304
 
   Unicode dir = NULL;
305
 
   Unicode fileName = NULL;
306
 
 
307
 
   *presult = NULL;
308
 
 
309
 
   if (tag && File_IsFullPath(tag)) {
310
 
      File_GetPathName(tag, &dir, &fileName);
311
 
   } else {
312
 
      dir = Util_GetSafeTmpDir(TRUE);
313
 
      fileName = Unicode_Duplicate(tag ? tag : "vmware");
314
 
   }
315
 
 
316
 
   fd = File_MakeTempEx(dir, fileName, presult);
317
 
 
318
 
   Unicode_Free(dir);
319
 
   Unicode_Free(fileName);
320
 
 
321
 
   return fd;
322
 
}
323
 
 
324
 
 
325
 
/*
326
 
 *-----------------------------------------------------------------------------
327
 
 *
328
 
 * UtilAcceptableSafeTmpDir --
329
 
 *
330
 
 *      Determines if the specified path is acceptable as the safe
331
 
 *      temp directory.  The directory must either be creatable
332
 
 *      with the appropriate permissions and userId or it must
333
 
 *      already exist with those settings.
334
 
 *
335
 
 * Results:
336
 
 *      TRUE if path is acceptible, FALSE otherwise
337
 
 *
338
 
 * Side effects:
339
 
 *      Directory may be created
340
 
 *
341
 
 *-----------------------------------------------------------------------------
342
 
 */
343
 
 
344
 
static Bool
345
 
UtilAcceptableSafeTmpDir(const char *dirname,  // IN
346
 
                         int userId)           // IN
347
 
{
348
 
   Bool result;
349
 
   static const mode_t mode = 0700;
350
 
 
351
 
   result = (Posix_Mkdir(dirname, mode) == 0);
352
 
   if (!result) {
353
 
      int error = errno;
354
 
 
355
 
      if (EEXIST == error) {
356
 
         struct stat st;
357
 
 
358
 
         /*
359
 
          * The name already exists. Check that it is what we want: a
360
 
          * directory owned by the current effective user with
361
 
          * permissions 'mode'. It is crucial to use lstat() instead of
362
 
          * stat() here, because we do not want the name to be a symlink
363
 
          * (created by another user) pointing to a directory owned by
364
 
          * the current effective user with permissions 'mode'.
365
 
          */
366
 
 
367
 
         if (0 == Posix_Lstat(dirname, &st)) {
368
 
            /*
369
 
             * Our directory inherited S_ISGID if its parent had it. So it
370
 
             * is important to ignore that bit, and it is safe to do so
371
 
             * because that bit does not affect the owner's
372
 
             * permissions.
373
 
             */
374
 
 
375
 
            if (S_ISDIR(st.st_mode) &&
376
 
                (st.st_uid == userId) &&
377
 
                ((st.st_mode & 05777) == mode)) {
378
 
               result = TRUE;
379
 
            }
380
 
         }
381
 
      }
382
 
   }
383
 
 
384
 
   return result;
385
 
}
386
 
 
387
 
 
388
 
/*
389
 
 *-----------------------------------------------------------------------------
390
 
 *
391
 
 * UtilFindExistingSafeTmpDir --
392
 
 *
393
 
 *      Searches the directory baseTmpDir to see if any subdirectories
394
 
 *      are suitable to use as the safe temp directory.  The safe temp
395
 
 *      directory must have the correct permissions and userId.
396
 
 *
397
 
 * Results:
398
 
 *      Path to discovered safe temp directory (must be freed).
399
 
 *      NULL returned if no suitable directory is found.
400
 
 *
401
 
 * Side effects:
402
 
 *      None
403
 
 *
404
 
 *-----------------------------------------------------------------------------
405
 
 */
406
 
 
407
 
static Unicode
408
 
UtilFindExistingSafeTmpDir(uid_t userId,             // IN
409
 
                           const char * userName,    // IN
410
 
                           const char * baseTmpDir)  // IN
411
 
{
412
 
   int i;
413
 
   int numFiles;
414
 
   Unicode pattern;
415
 
   Unicode tmpDir = NULL;
416
 
   Unicode *fileList = NULL;
417
 
   
418
 
   /*
419
 
    * We always use the pattern PRODUCT-USER-xxxx when creating
420
 
    * alternative safe temp directories, so check for ones with
421
 
    * those names and the appropriate permissions.
422
 
    */
423
 
   
424
 
   pattern = Unicode_Format("%s-%s-", PRODUCT_GENERIC_NAME_LOWER, userName);
425
 
   if (pattern == NULL) {
426
 
      return NULL;
427
 
   }
428
 
 
429
 
   numFiles = File_ListDirectory(baseTmpDir, &fileList);
430
 
 
431
 
   if (numFiles == -1) {
432
 
      Unicode_Free(pattern);
433
 
      return NULL;
434
 
   }
435
 
 
436
 
   for (i = 0; i < numFiles; i++) {
437
 
       if (Unicode_StartsWith(fileList[i], pattern)) {
438
 
          Unicode path = Unicode_Join(baseTmpDir, DIRSEPS, fileList[i],
439
 
                                      NULL);
440
 
 
441
 
          if (File_IsDirectory(path) &&
442
 
              UtilAcceptableSafeTmpDir(path, userId)) {
443
 
             tmpDir = path;
444
 
             break;
445
 
          }
446
 
 
447
 
          Unicode_Free(path);
448
 
       }
449
 
   }
450
 
 
451
 
   Unicode_FreeList(fileList, numFiles);
452
 
   Unicode_Free(pattern);
453
 
 
454
 
   return tmpDir;
455
 
}
456
 
 
457
 
/*
458
 
 *-----------------------------------------------------------------------------
459
 
 *
460
 
 * UtilCreateSafeTmpDir --
461
 
 *
462
 
 *      Creates a new directory within baseTmpDir with the correct 
463
 
 *      permissions and userId to ensure it is safe from symlink attacks.
464
 
 *
465
 
 * Results:
466
 
 *      Path to created safe temp directory (must be freed).
467
 
 *      NULL returned if no suitable directory could be created.
468
 
 *
469
 
 * Side effects:
470
 
 *      Directory may be created.
471
 
 *
472
 
 *-----------------------------------------------------------------------------
473
 
 */
474
 
 
475
 
static char *
476
 
UtilCreateSafeTmpDir(uid_t userId,             // IN
477
 
                     const char * userName,    // IN
478
 
                     const char * baseTmpDir)  // IN
479
 
{
480
 
   static const int MAX_DIR_ITERS = 250;
481
 
   char *tmpDir = NULL;
482
 
   int curDirIter;
483
 
 
484
 
   curDirIter = 0;
485
 
   while (TRUE) {
486
 
      unsigned int suffix;
487
 
      
488
 
      /* 
489
 
       * We use a crypographically strong random number which is
490
 
       * overkill for this purpose but makes it slightly more likely
491
 
       * that we will create an unused name than if we had simply tried
492
 
       * suffixes in numeric order.
493
 
       */
494
 
 
495
 
      if (!Random_Crypto(sizeof(suffix), &suffix)) {
496
 
         Warning("%s: Call to Random_Crypto failed.\n", __FUNCTION__);
497
 
         break;
498
 
      }
499
 
      
500
 
      tmpDir = Str_Asprintf(NULL, "%s"DIRSEPS"%s-%s-%u", baseTmpDir,
501
 
                            PRODUCT_GENERIC_NAME_LOWER, userName, suffix);
502
 
      
503
 
      if (!tmpDir) {
504
 
         Warning("%s: Out of memory error.\n", __FUNCTION__);
505
 
         break;
506
 
      }
507
 
      
508
 
      if (UtilAcceptableSafeTmpDir(tmpDir, userId)) {
509
 
         break;
510
 
      }
511
 
      
512
 
      if (++curDirIter > MAX_DIR_ITERS) {
513
 
         Warning("%s: Failed to create a safe temporary "
514
 
               "directory, path \"%s\". The maximum number of attempts was "
515
 
               "exceeded.\n", __FUNCTION__, tmpDir);
516
 
         free(tmpDir);
517
 
         tmpDir = NULL;
518
 
         break;
519
 
      }
520
 
      
521
 
      free(tmpDir);
522
 
      tmpDir = NULL;
523
 
   }
524
 
 
525
 
   return tmpDir;
526
 
}
527
 
 
528
 
/*
529
 
 *-----------------------------------------------------------------------------
530
 
 *
531
 
 * Util_GetSafeTmpDir --
532
 
 *
533
 
 *      Return a safe temporary directory (i.e. a temporary directory
534
 
 *      which is not prone to symlink attacks, because it is only
535
 
 *      writable by the current effective user). Guaranteed to return
536
 
 *      the same directory every time it is called during the lifetime
537
 
 *      of the current process (unless that directory is deleted while
538
 
 *      the process is running).
539
 
 *
540
 
 * Results:
541
 
 *      The allocated directory path on success.
542
 
 *      NULL on failure.
543
 
 *
544
 
 * Side effects:
545
 
 *      None.
546
 
 *
547
 
 *-----------------------------------------------------------------------------
548
 
 */
549
 
 
550
 
char *
551
 
Util_GetSafeTmpDir(Bool useConf) // IN
552
 
{
553
 
   static Atomic_Ptr lckStorage;
554
 
   static char *safeDir;
555
 
   char *tmpDir = NULL;
556
 
   char *baseTmpDir = NULL;
557
 
   char *userName = NULL;
558
 
   uid_t userId;
559
 
   SyncMutex *lck;
560
 
 
561
 
   userId = geteuid();
562
 
 
563
 
   /* Get and take lock for our safe dir. */
564
 
   lck = SyncMutex_CreateSingleton(&lckStorage);
565
 
   SyncMutex_Lock(lck);
566
 
 
567
 
   /*
568
 
    * Check if we've created a temporary dir already and if it is
569
 
    * still usable.
570
 
    */
571
 
   if (safeDir && UtilAcceptableSafeTmpDir(safeDir, userId)) {
572
 
      tmpDir = Util_SafeStrdup(safeDir);
573
 
      goto exit;
574
 
   }
575
 
 
576
 
   /* We don't have a useable temporary dir, create one. */
577
 
   baseTmpDir = File_GetTmpDir(useConf);
578
 
   
579
 
   if (!baseTmpDir) {
580
 
      Warning("%s: File_GetTmpDir failed.\n", __FUNCTION__);
581
 
      goto exit;
582
 
   }
583
 
   
584
 
   userName = UtilGetUserName(userId);
585
 
   
586
 
   if (!userName) {
587
 
      Warning("%s: UtilGetUserName failed, using numeric ID "
588
 
              "as username instead.\n", __FUNCTION__);
589
 
      
590
 
      /* Fallback on just using the userId as the username. */
591
 
      userName = Str_Asprintf(NULL, "uid-%d", userId);
592
 
      
593
 
      if (!userName) {
594
 
         Warning("%s: Str_Asprintf error.\n", __FUNCTION__);
595
 
         goto exit;
596
 
      }
597
 
   }
598
 
   
599
 
   tmpDir = Str_Asprintf(NULL, "%s"DIRSEPS"%s-%s", baseTmpDir,
600
 
                         PRODUCT_GENERIC_NAME_LOWER, userName);
601
 
   
602
 
   if (!tmpDir) {
603
 
      Warning("%s: Out of memory error.\n", __FUNCTION__);
604
 
      goto exit;
605
 
   }
606
 
 
607
 
   if (!UtilAcceptableSafeTmpDir(tmpDir, userId)) {
608
 
      /*
609
 
       * We didn't get our first choice for the safe temp directory.
610
 
       * Search through the unsafe tmp directory to see if there is
611
 
       * an acceptable one to use.
612
 
       */
613
 
 
614
 
      free(tmpDir);
615
 
 
616
 
      tmpDir = UtilFindExistingSafeTmpDir(userId, userName, baseTmpDir);
617
 
 
618
 
      if (!tmpDir) {
619
 
         /*
620
 
          * We didn't find any usable directories, so try to create one
621
 
          * now.
622
 
          */
623
 
 
624
 
         tmpDir = UtilCreateSafeTmpDir(userId, userName, baseTmpDir);
625
 
      }
626
 
   }
627
 
 
628
 
   if (tmpDir) {
629
 
      /*
630
 
       * We have successfully created a temporary directory, remember it for
631
 
       * future calls.
632
 
       */
633
 
 
634
 
      free(safeDir);
635
 
      safeDir = Util_SafeStrdup(tmpDir);
636
 
   }
637
 
 
638
 
  exit:
639
 
   SyncMutex_Unlock(lck);
640
 
   free(baseTmpDir);
641
 
   free(userName);
642
 
 
643
 
   return tmpDir;
644
 
}
645
 
 
646
 
#endif // __linux__
647
 
 
648
 
 
649
 
#if defined(__linux__) || defined(__FreeBSD__) || defined(sun)
650
 
/*
651
 
 *----------------------------------------------------------------------------
652
 
 *
653
 
 * Util_GetProcessName --
654
 
 *
655
 
 *    Tries to locate the process name of the specified process id.  The
656
 
 *    process' name is placed in bufOut.
657
 
 *
658
 
 * Results:
659
 
 *    TRUE on success, FALSE on failure.
660
 
 *
661
 
 * Side effects:
662
 
 *    None.
663
 
 *
664
 
 *----------------------------------------------------------------------------
665
 
 */
666
 
 
667
 
Bool
668
 
Util_GetProcessName(pid_t pid,         // IN : process id
669
 
                    char *bufOut,      // OUT: output buffer
670
 
                    size_t bufOutSize) // IN : buffer size
671
 
{
672
 
   int fd;
673
 
   int nread;
674
 
   char *psname;
675
 
   size_t psnameLen;
676
 
   char fileName[MAXPATHLEN];
677
 
#ifdef sun
678
 
   char buf[sizeof (psinfo_t)];
679
 
#else
680
 
   char buf[PSINFOSZ];
681
 
   char psinfo[PSINFOSZ];
682
 
#endif
683
 
 
684
 
   ASSERT(bufOut);
685
 
 
686
 
   /*
687
 
    * Open up /proc/<pid>/status on Linux/FreeBSD, and /proc/<pid>/psinfo on
688
 
    * Solaris.
689
 
    */
690
 
 
691
 
   Str_Sprintf(fileName, sizeof fileName, "/proc/%"FMTPID"/" PROCFILE, pid);
692
 
 
693
 
   fd = Posix_Open(fileName, O_RDONLY);
694
 
   if (fd < 0) {
695
 
      Log("%s: Error: cannot open %s\n", __FUNCTION__, fileName);
696
 
 
697
 
      return FALSE;
698
 
   }
699
 
 
700
 
   nread = read(fd, buf, sizeof buf);
701
 
#ifdef sun
702
 
   if (nread != sizeof buf) {
703
 
#else
704
 
   if (nread < 0) {
705
 
#endif
706
 
      Log("%s: Error: could not read %s\n", __FUNCTION__, fileName);
707
 
      close(fd);
708
 
 
709
 
      return FALSE;
710
 
   }
711
 
 
712
 
   close(fd);
713
 
 
714
 
#ifdef sun
715
 
   psname = ((psinfo_t *)buf)->pr_fname;
716
 
#else /* Linux & FreeBSD */
717
 
   ASSERT(nread <= sizeof buf);
718
 
   buf[nread == sizeof buf ? nread - 1 : nread] = '\0';
719
 
 
720
 
   /*
721
 
    * Parse the plain text formatting of the status file.  Note that PSINFOFMT
722
 
    * contains a format modifier to ensure psinfo is not overrun.
723
 
    */
724
 
 
725
 
   if (sscanf(buf, PRE PSINFOFMT POST, psinfo) != 1) {
726
 
      Log("%s: Error, could not parse contents of %s\n", __FUNCTION__,
727
 
          fileName);
728
 
 
729
 
      return FALSE;
730
 
   }
731
 
 
732
 
   Escape_UnescapeCString(psinfo);
733
 
 
734
 
   psname = psinfo;
735
 
#endif /* sun */
736
 
 
737
 
   psnameLen = strlen(psname);
738
 
   if (psnameLen + 1 > bufOutSize) {
739
 
      Log("%s: Error, process name (%"FMTSZ"u bytes) is larger "
740
 
          "than output buffer\n", __FUNCTION__, psnameLen);
741
 
 
742
 
      return FALSE;
743
 
   }
744
 
 
745
 
   memcpy(bufOut, psname, psnameLen + 1);
746
 
 
747
 
   return TRUE;
748
 
}
749
 
#endif
750
 
 
751
 
#if defined(VMX86_STATS)
752
 
#if defined(__linux__) && !defined(VMX86_SERVER)
753
 
/*
754
 
 *----------------------------------------------------------------------------
755
 
 *
756
 
 * UtilAllocCStArrays --
757
 
 *
758
 
 *      (Re-)Allocate data arrays for UtilReadSysCStRes and UtilReadProcCStRes.
759
 
 *
760
 
 * Results:
761
 
 *      TRUE if successful.
762
 
 *
763
 
 * Side effects:
764
 
 *      None.
765
 
 *
766
 
 *----------------------------------------------------------------------------
767
 
 */
768
 
 
769
 
static Bool
770
 
UtilAllocCStArrays(uint32 ncpus,        // IN
771
 
                   uint32 nstates,      // IN
772
 
                   uint64 **transitns,  // OUT
773
 
                   uint64 **residency,  // OUT
774
 
                   uint64 **transTime,  // OUT
775
 
                   uint64 **residTime)  // OUT
776
 
{
777
 
   free(*transitns);
778
 
   free(*residency);
779
 
   free(*transTime);
780
 
   free(*residTime);
781
 
 
782
 
   *transitns = calloc(nstates * ncpus, sizeof **transitns);
783
 
   *residency = calloc(nstates * ncpus, sizeof **residency);
784
 
   *transTime = calloc(ncpus, sizeof **transTime);
785
 
   *residTime = calloc(ncpus, sizeof **residTime);
786
 
 
787
 
   if (!*transitns || !*residency || !*transTime || !*residTime) {
788
 
      free(*transitns);
789
 
      free(*residency);
790
 
      free(*transTime);
791
 
      free(*residTime);
792
 
      Warning("%s: Cannot allocate memory for C-state queries\n",
793
 
              __FUNCTION__);
794
 
 
795
 
      return FALSE;
796
 
   }
797
 
 
798
 
   return TRUE;
799
 
}
800
 
 
801
 
 
802
 
/*
803
 
 *----------------------------------------------------------------------------
804
 
 *
805
 
 * UtilReadSysCStRes --
806
 
 * UtilReadProcCStRes --
807
 
 *
808
 
 *      Read the C-state residency statistics under /sys and /proc
809
 
 *      respectively. UtilReadSysCStRes should take precedence over
810
 
 *      UtilReadProcCStRes as /proc/acpi is getting replaced by sysfs
811
 
 *      in newer kernels. See Util_QueryCStResidency for description of
812
 
 *      parameters.
813
 
 *
814
 
 * Results:
815
 
 *      TRUE if successful.
816
 
 *
817
 
 * Side effects:
818
 
 *      None.
819
 
 *
820
 
 *----------------------------------------------------------------------------
821
 
 */
822
 
 
823
 
static Bool
824
 
UtilReadSysCStRes(DIR *dir,                     // IN
825
 
                  uint32 *numCpus,              // IN/OUT
826
 
                  uint32 *numCStates,           // IN/OUT
827
 
                  uint64 **transitns,           // OUT
828
 
                  uint64 **residency,           // OUT
829
 
                  uint64 **transTime,           // OUT
830
 
                  uint64 **residTime)           // OUT
831
 
{
832
 
   struct dirent *cpuEntry;
833
 
   DIR *cpuDir;
834
 
   struct dirent *cstateEntry;
835
 
   char pathname[PATH_MAX + 1];
836
 
   uint32 cpu = 0;
837
 
   uint32 cl = 0;
838
 
 
839
 
   /* Determine the number of cpus and c-states. */
840
 
   while ((cpuEntry = readdir(dir))) {
841
 
      if (Str_Strncasecmp(cpuEntry->d_name, "cpu", 3) == 0 &&
842
 
          isdigit(cpuEntry->d_name[3])) {
843
 
         cpu++;
844
 
         if (cl != 0) {         /* already found the number of c states */
845
 
            continue;
846
 
         }
847
 
         if (Str_Snprintf(pathname, sizeof pathname,
848
 
                          SYS_CSTATE_DIR"/%s/cpuidle",
849
 
                          cpuEntry->d_name) <= 0) {
850
 
            LOG(0, ("%s: Str_Snprintf failed\n", __FUNCTION__));
851
 
 
852
 
            return FALSE;
853
 
         }
854
 
         cpuDir = Posix_OpenDir(pathname);
855
 
         if (cpuDir != NULL) {
856
 
            uint32 cnum;
857
 
 
858
 
            while ((cstateEntry = readdir(cpuDir))) {
859
 
               if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) == 0 &&
860
 
                   sscanf(cstateEntry->d_name + 5, "%u", &cnum) == 1 &&
861
 
                   cnum > cl) {
862
 
                  cl = cnum;    /* state0 will be ignored */
863
 
               }
864
 
            }
865
 
            closedir(cpuDir);
866
 
         }
867
 
      }
868
 
   }
869
 
   if (cpu == 0 || cl == 0) {
870
 
      return FALSE;
871
 
   }
872
 
 
873
 
   if (*numCpus != cpu || *numCStates != cl) {
874
 
      if (!UtilAllocCStArrays(cpu, cl, transitns, residency, transTime,
875
 
                              residTime)) {
876
 
         return FALSE;
877
 
      }
878
 
      *numCpus = cpu;
879
 
      *numCStates = cl;
880
 
   }
881
 
 
882
 
   rewinddir(dir);
883
 
   cpu = 0;
884
 
   while ((cpuEntry = readdir(dir))) {
885
 
      int pathlen;
886
 
      VmTimeType timeUS;
887
 
 
888
 
      if (Str_Strncasecmp(cpuEntry->d_name, "cpu", 3) != 0 ||
889
 
          !isdigit(cpuEntry->d_name[3])) {
890
 
         continue;
891
 
      }
892
 
      pathlen = Str_Snprintf(pathname, sizeof pathname,
893
 
                             SYS_CSTATE_DIR"/%s/cpuidle", cpuEntry->d_name);
894
 
      if (pathlen <= 0) {
895
 
         LOG(0, ("%s: Str_Snprintf for '%s/cpuidle' failed\n", __FUNCTION__,
896
 
                 cpuEntry->d_name));
897
 
 
898
 
         return FALSE;
899
 
      }
900
 
      cpuDir = Posix_OpenDir(pathname);
901
 
      if (cpuDir == NULL) {
902
 
         LOG(0, ("%s: Failed to open directory %s\n", __FUNCTION__, pathname));
903
 
         continue;
904
 
      }
905
 
 
906
 
      /*
907
 
       * Under the "cpuidle" directory, there is one "stateX" directory for
908
 
       * each C-state.  We ignore "state0", i.e. C0, which is the running state.
909
 
       * Under each "stateX" directory, there is a "usage" file which contains
910
 
       * the number of entries into that state, and a "time" file which
911
 
       * contains the total residency in that state.
912
 
       */
913
 
 
914
 
      while ((cstateEntry = readdir(cpuDir))) {
915
 
         FILE *statsFile;
916
 
         int result;
917
 
         uint32 index;
918
 
 
919
 
         if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) != 0) {
920
 
            continue;
921
 
         }
922
 
         if (sscanf(cstateEntry->d_name + 5, "%u", &cl) != 1 || cl == 0) {
923
 
            continue;
924
 
         }
925
 
         cl--;          /* ignoring state0 -- cl == 0 -> state1 */
926
 
         index = *numCStates * cpu + cl;
927
 
 
928
 
         if (Str_Snprintf(pathname + pathlen, sizeof pathname - pathlen,
929
 
                          "/%s/usage", cstateEntry->d_name) <= 0) {
930
 
            LOG(0, ("%s: Str_Snprintf for 'usage' failed\n", __FUNCTION__));
931
 
            closedir(cpuDir);
932
 
 
933
 
            return FALSE;
934
 
         }
935
 
         statsFile = Posix_Fopen(pathname, "r");
936
 
         if (statsFile == NULL) {
937
 
            continue;
938
 
         }
939
 
         result = fscanf(statsFile, "%"FMT64"u", &(*transitns)[index]);
940
 
         fclose(statsFile);
941
 
         if (result <= 0) {
942
 
            continue;
943
 
         }
944
 
 
945
 
         if (Str_Snprintf(pathname + pathlen, sizeof pathname - pathlen,
946
 
                          "/%s/time", cstateEntry->d_name) <= 0) {
947
 
            LOG(0, ("%s: Str_Snprintf for 'time' failed\n", __FUNCTION__));
948
 
            closedir(cpuDir);
949
 
 
950
 
            return FALSE;
951
 
         }
952
 
         statsFile = Posix_Fopen(pathname, "r");
953
 
         if (statsFile == NULL) {
954
 
            continue;
955
 
         }
956
 
         result = fscanf(statsFile, "%"FMT64"u", &(*residency)[index]);
957
 
         fclose(statsFile);
958
 
         if (result <= 0) {
959
 
            continue;
960
 
         }
961
 
      }
962
 
      closedir(cpuDir);
963
 
 
964
 
      timeUS = Hostinfo_SystemTimerUS();
965
 
      if (timeUS <= 0) {
966
 
         LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__));
967
 
 
968
 
         return FALSE;
969
 
      }
970
 
      (*transTime)[cpu] = timeUS;
971
 
      (*residTime)[cpu] = timeUS;
972
 
      cpu++;
973
 
   }
974
 
 
975
 
   return cpu > 0;
976
 
}
977
 
 
978
 
 
979
 
static Bool
980
 
UtilReadProcCStRes(DIR *dir,                    // IN
981
 
                   uint32 *numCpus,             // IN/OUT
982
 
                   uint32 *numCStates,          // IN/OUT
983
 
                   uint64 **transitns,          // OUT
984
 
                   uint64 **residency,          // OUT
985
 
                   uint64 **transTime,          // OUT
986
 
                   uint64 **residTime)          // OUT
987
 
{
988
 
   struct dirent *cpuEntry;
989
 
   uint32 cpu = 0;
990
 
 
991
 
   /* Determine the number of cpus. */
992
 
   while ((cpuEntry = readdir(dir))) {
993
 
      if (cpuEntry->d_name[0] != '.') {
994
 
         cpu++;
995
 
      }
996
 
   }
997
 
   if (cpu == 0) {
998
 
      return FALSE;
999
 
   }
1000
 
 
1001
 
   if (*numCpus != cpu) {
1002
 
      /*
1003
 
       * We do not know the number of C-states supported until we read the
1004
 
       * file, so we allocate for MAX_C_STATES and determine *numCStates later.
1005
 
       */
1006
 
 
1007
 
      if (!UtilAllocCStArrays(cpu, MAX_C_STATES, transitns, residency,
1008
 
                              transTime, residTime)) {
1009
 
         return FALSE;
1010
 
      }
1011
 
      *numCpus = cpu;
1012
 
      *numCStates = 0;
1013
 
   }
1014
 
 
1015
 
   rewinddir(dir);
1016
 
   cpu = 0;
1017
 
   while ((cpuEntry = readdir(dir))) {
1018
 
      char pathname[PATH_MAX + 1];
1019
 
      char *line;
1020
 
      size_t lineSize;
1021
 
      FILE *powerFile;
1022
 
      uint32 cl;
1023
 
      VmTimeType timeUS;
1024
 
 
1025
 
      if (cpuEntry->d_name[0] == '.') {
1026
 
         continue;
1027
 
      }
1028
 
      if (Str_Snprintf(pathname, sizeof pathname, PROC_CSTATE_DIR"/%s/power",
1029
 
                       cpuEntry->d_name) <= 0) {
1030
 
         LOG(0, ("%s: Str_Snprintf for '%s/power' failed\n", __FUNCTION__,
1031
 
                 cpuEntry->d_name));
1032
 
 
1033
 
         return FALSE;
1034
 
      }
1035
 
      powerFile = Posix_Fopen(pathname, "r");
1036
 
      if (powerFile == NULL) {
1037
 
         continue;
1038
 
      }
1039
 
 
1040
 
      cl = 0;
1041
 
      while (StdIO_ReadNextLine(powerFile, &line, 0,
1042
 
                                &lineSize) == StdIO_Success) {
1043
 
         char *ptr;
1044
 
         uint32 index = *numCStates * cpu + cl;
1045
 
 
1046
 
         if ((ptr = Str_Strnstr(line, "usage[", lineSize))) {
1047
 
            sscanf(ptr + 6, "%"FMT64"u]", &(*transitns)[index]);
1048
 
            if ((ptr = Str_Strnstr(line, "duration[", lineSize))) {
1049
 
               sscanf(ptr + 9, "%"FMT64"u]", &(*residency)[index]);
1050
 
               cl++;
1051
 
            }
1052
 
         }
1053
 
         free(line);
1054
 
      }
1055
 
      fclose(powerFile);
1056
 
 
1057
 
      timeUS = Hostinfo_SystemTimerUS();
1058
 
      if (timeUS <= 0) {
1059
 
         LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__));
1060
 
 
1061
 
         return FALSE;
1062
 
      }
1063
 
      (*transTime)[cpu] = timeUS;
1064
 
      (*residTime)[cpu] = (uint64)((double)timeUS * FREQ_ACPI);
1065
 
      if (*numCStates == 0) {
1066
 
         *numCStates = cl;
1067
 
      }
1068
 
      cpu++;
1069
 
   }
1070
 
 
1071
 
   return cpu > 0 && *numCStates > 0;
1072
 
}
1073
 
 
1074
 
 
1075
 
/*
1076
 
 *----------------------------------------------------------------------------
1077
 
 *
1078
 
 * Util_QueryCStResidency --
1079
 
 *
1080
 
 *      Query CPU's C-state residency statistics exposed by the host OS.
1081
 
 *      On Linux, this is done via either the sysfs or /proc/acpi interface.
1082
 
 *
1083
 
 *      The parameters transitns, residency, transTime and residTime are
1084
 
 *      pointers to uint64 arrays, whose dimensions are specified by
1085
 
 *      *numCpus and/or *numCStates:
1086
 
 *      transitns -- number of trasitions into each c-state for each CPU
1087
 
 *      residency -- time in each c-state for each CPU (in some opaque unit)
1088
 
 *      transTime -- timestamp (microseconds) for transitns data, per CPU
1089
 
 *      residTime -- timestamp for residency data, per CPU (in same unit as
1090
 
 *                   residency)
1091
 
 *
1092
 
 *      If the dimensions specified are too small, the arrays are freed
1093
 
 *      and new memory allocated.
1094
 
 *
1095
 
 * Results:
1096
 
 *      TRUE if successful.
1097
 
 *
1098
 
 * Side Effects:
1099
 
 *      None.
1100
 
 *
1101
 
 *----------------------------------------------------------------------------
1102
 
 */
1103
 
 
1104
 
Bool
1105
 
Util_QueryCStResidency(uint32 *numCpus,         // IN/OUT
1106
 
                       uint32 *numCStates,      // IN/OUT
1107
 
                       uint64 **transitns,      // OUT
1108
 
                       uint64 **residency,      // OUT
1109
 
                       uint64 **transTime,      // OUT
1110
 
                       uint64 **residTime)      // OUT
1111
 
{
1112
 
   DIR *dir;
1113
 
   Bool ret = FALSE;
1114
 
 
1115
 
   dir = Posix_OpenDir(SYS_CSTATE_DIR);
1116
 
   if (dir) {
1117
 
      ret = UtilReadSysCStRes(dir, numCpus, numCStates, transitns, residency,
1118
 
                              transTime, residTime);
1119
 
      closedir(dir);
1120
 
   }
1121
 
 
1122
 
   if (!ret) {
1123
 
      dir = Posix_OpenDir(PROC_CSTATE_DIR);
1124
 
      if (dir) {
1125
 
         ret = UtilReadProcCStRes(dir, numCpus, numCStates, transitns,
1126
 
                                  residency, transTime, residTime);
1127
 
         closedir(dir);
1128
 
      }
1129
 
   }
1130
 
 
1131
 
   return ret;
1132
 
}
1133
 
 
1134
 
#else   // #if defined(__linux__) && !defined(VMX86_SERVER)
1135
 
 
1136
 
Bool
1137
 
Util_QueryCStResidency(uint32 *numCpus,         // IN/OUT
1138
 
                       uint32 *numCStates,      // IN/OUT
1139
 
                       uint64 **transitns,      // OUT
1140
 
                       uint64 **residency,      // OUT
1141
 
                       uint64 **transTime,      // OUT
1142
 
                       uint64 **residTime)      // OUT
1143
 
{
1144
 
   return FALSE;
1145
 
}
1146
 
#endif
1147
 
#endif  // #if defined(VMX86_STATS)