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

« back to all changes in this revision

Viewing changes to guestd/toolsDaemon.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) 2001 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
 
/*
21
 
 * toolsDaemon.c --
22
 
 *
23
 
 *    Platform independent methods used by the tools daemon.
24
 
 *    The tools daemon does the following:
25
 
 *      -starts automatically with the guest
26
 
 *      -syncs the guest time to the host
27
 
 *      -executes scripts on state change requests from the VMX
28
 
 *      -listens for other TCLO cmds through the backdoor
29
 
 */
30
 
 
31
 
#ifdef __cplusplus
32
 
extern "C" {
33
 
#endif
34
 
 
35
 
#include <stdio.h>
36
 
#include <string.h>
37
 
#include <stdlib.h>
38
 
#include <stdarg.h>
39
 
 
40
 
#ifdef _WIN32
41
 
#   include <windows.h>
42
 
#   include "win32u.h"
43
 
#   include "hgfsUsabilityLib.h"
44
 
#   include "rescaps.h"
45
 
#   include "ServiceHelpers.h"
46
 
#endif
47
 
 
48
 
 
49
 
#include "vmware.h"
50
 
#include "toolsDaemon.h"
51
 
#include "vm_version.h"
52
 
#include "vm_app.h"
53
 
#include "message.h"
54
 
#include "eventManager.h"
55
 
#include "debug.h"
56
 
#include "guestApp.h"
57
 
#include "rpcout.h"
58
 
#include "rpcin.h"
59
 
#include "hostinfo.h"
60
 
#include "strutil.h"
61
 
#include "str.h"
62
 
#include "msg.h"
63
 
#include "backdoor.h"
64
 
#include "backdoor_def.h"
65
 
#include "system.h"
66
 
#include "netutil.h"
67
 
#include "hgfsServerManager.h"
68
 
#include "conf.h"
69
 
#include "foundryToolsDaemon.h"
70
 
#include "util.h"
71
 
#include "vmcheck.h"
72
 
#include "guestInfo.h"
73
 
 
74
 
#ifndef N_PLAT_NLM
75
 
#include "vm_atomic.h"
76
 
#include "hostinfo.h"
77
 
#include "guestInfoServer.h"
78
 
#include "syncDriver.h"
79
 
#endif // #ifndef N_PLAT_NLM
80
 
 
81
 
#if !defined(__FreeBSD__) && !defined(sun) && !defined(N_PLAT_NLM)
82
 
#include "deployPkg.h"
83
 
#endif
84
 
 
85
 
#ifdef TOOLSDAEMON_HAS_RESOLUTION
86
 
#   include "resolution.h"
87
 
#endif
88
 
 
89
 
/* in 1/100 of a second */
90
 
#define RPCIN_POLL_TIME      10
91
 
/* sync the time once a minute */
92
 
#define TIME_SYNC_TIME     6000
93
 
/* only PERCENT_CORRECTION percent is corrected everytime */
94
 
#define PERCENT_CORRECTION   50
95
 
 
96
 
/*
97
 
 * Table mapping state changes to their conf file names.
98
 
 */
99
 
/*
100
 
 * Bug 294328:  Mac OS guests do not (yet) support the state change RPCs.
101
 
 */
102
 
#ifndef __APPLE__
103
 
static const char *stateChgConfNames[] = {
104
 
   NULL,                     /* NONE */
105
 
   CONFNAME_POWEROFFSCRIPT,  /* HALT */
106
 
   CONFNAME_POWEROFFSCRIPT,  /* REBOOT */
107
 
   CONFNAME_POWERONSCRIPT,   /* POWERON */
108
 
   CONFNAME_RESUMESCRIPT,    /* RESUME */
109
 
   CONFNAME_SUSPENDSCRIPT,   /* SUSPEND */
110
 
};
111
 
#endif
112
 
 
113
 
DblLnkLst_Links *ToolsDaemonEventQueue = NULL;  // main loop event queue
114
 
static char *guestTempDirectory = NULL;
115
 
 
116
 
void ToolsDaemon_InitializeForeignVM(ToolsDaemon_Data *toolsDaemonData);
117
 
void ToolsDaemon_ShutdownForeignVM(void);
118
 
 
119
 
 
120
 
/*
121
 
 *-----------------------------------------------------------------------------
122
 
 *
123
 
 * ToolsDaemon_SyncTime --
124
 
 *
125
 
 *    Set the guest OS time to the host OS time
126
 
 *
127
 
 * Return value:
128
 
 *    TRUE on success
129
 
 *    FALSE on failure (detail is displayed)
130
 
 *
131
 
 * Side effects:
132
 
 *    None
133
 
 *
134
 
 *-----------------------------------------------------------------------------
135
 
 */
136
 
 
137
 
Bool
138
 
ToolsDaemon_SyncTime(Bool slewCorrection,  // IN: Is clock slewing enabled?
139
 
                     Bool syncOnce,        // IN: Is this function called in a loop?
140
 
                     void *toolsData)      // IN: Opaque data
141
 
{
142
 
   Backdoor_proto bp;
143
 
   int64 maxTimeLag;
144
 
   int64 interruptLag;
145
 
   int64 guestSecs;
146
 
   int64 guestUsecs;
147
 
   int64 hostSecs;
148
 
   int64 hostUsecs;
149
 
   int64 diffSecs;
150
 
   int64 diffUsecs;
151
 
   int64 diff;
152
 
   ToolsDaemon_Data *data = (ToolsDaemon_Data *) toolsData;
153
 
   Bool timeLagCall = FALSE;
154
 
#ifdef VMX86_DEBUG
155
 
   static int64 lastHostSecs = 0;
156
 
   int64 secs1, usecs1;
157
 
   int64 secs2, usecs2;
158
 
 
159
 
   System_GetCurrentTime(&secs1, &usecs1);
160
 
#endif
161
 
 
162
 
   Debug("Daemon: Synchronizing time\n");
163
 
 
164
 
   /* 
165
 
    * We need 3 things from the host, and there exist 3 different versions of
166
 
    * the calls (described further below):
167
 
    * 1) host time
168
 
    * 2) maximum time lag allowed (config option), which is a 
169
 
    *    threshold that keeps the tools from being over eager about
170
 
    *    resetting the time when it is only a little bit off.
171
 
    * 3) interrupt lag
172
 
    *
173
 
    * First 2 versions of the call add interrupt lag to the maximum allowed
174
 
    * time lag, where as in the last call it is returned separately.
175
 
    *
176
 
    * Three versions of the call:
177
 
    *
178
 
    * - BDOOR_CMD_GETTIME: suffers from a 136-year overflow problem that
179
 
    *   cannot be corrected without breaking backwards compatibility with
180
 
    *   older Tools. So, we have the newer BDOOR_CMD_GETTIMEFULL, which is
181
 
    *   overflow safe.
182
 
    *
183
 
    * - BDOOR_CMD_GETTIMEFULL: overcomes the problem above.
184
 
    *
185
 
    * - BDOOR_CMD_GETTIMEFULL_WITH_LAG: Both BDOOR_CMD_GETTIMEFULL and
186
 
    *   BDOOR_CMD_GETTIME returns max lag limit as interrupt lag + the maximum
187
 
    *   allowed time lag. BDOOR_CMD_GETTIMEFULL_WITH_LAG separates these two
188
 
    *   values. This is helpful when synchronizing time backwards by slewing
189
 
    *   the clock.
190
 
    *
191
 
    * We use BDOOR_CMD_GETTIMEFULL_WITH_LAG first and fall back to
192
 
    * BDOOR_CMD_GETTIMEFULL or BDOOR_CMD_GETTIME.
193
 
    *
194
 
    * Note that BDOOR_CMD_GETTIMEFULL and BDOOR_CMD_GETTIMEFULL_WITH_LAG will
195
 
    * not touch EAX when it succeeds. So we check for errors by comparing EAX to
196
 
    * BDOOR_MAGIC, which was set by the call to Backdoor() prior to touching the
197
 
    * backdoor port.
198
 
    */
199
 
   bp.in.cx.halfs.low = BDOOR_CMD_GETTIMEFULL_WITH_LAG;
200
 
   Backdoor(&bp);
201
 
   if (bp.out.ax.word == BDOOR_MAGIC) {
202
 
      hostSecs = ((uint64)bp.out.si.word << 32) | bp.out.dx.word;
203
 
      interruptLag = bp.out.di.word;
204
 
      timeLagCall = TRUE;
205
 
      Debug("Using BDOOR_CMD_GETTIMEFULL_WITH_LAG\n");
206
 
   } else {
207
 
      Debug("BDOOR_CMD_GETTIMEFULL_WITH_LAG not supported by current host, attempting "
208
 
            "BDOOR_CMD_GETTIMEFULL\n");
209
 
      interruptLag = 0;
210
 
      bp.in.cx.halfs.low = BDOOR_CMD_GETTIMEFULL;
211
 
      Backdoor(&bp);
212
 
      if (bp.out.ax.word == BDOOR_MAGIC) {
213
 
         hostSecs = ((uint64)bp.out.si.word << 32) | bp.out.dx.word;
214
 
      } else {
215
 
         Debug("BDOOR_CMD_GETTIMEFULL not supported by current host, attempting "
216
 
               "BDOOR_CMD_GETTIME\n");
217
 
         bp.in.cx.halfs.low = BDOOR_CMD_GETTIME;
218
 
         Backdoor(&bp);
219
 
         hostSecs = bp.out.ax.word;
220
 
      }
221
 
   }
222
 
   hostUsecs = bp.out.bx.word;
223
 
   maxTimeLag = bp.out.cx.word;
224
 
 
225
 
   if (hostSecs <= 0) {
226
 
      Warning("Invalid host OS time: %"FMT64"d secs, %"FMT64"d usecs.\n\n",
227
 
              hostSecs, hostUsecs);
228
 
 
229
 
      return FALSE;
230
 
   }
231
 
 
232
 
   /* Get the guest OS time */
233
 
   if (!System_GetCurrentTime(&guestSecs, &guestUsecs)) {
234
 
      Warning("Unable to retrieve the guest OS time: %s.\n\n", Msg_ErrString());
235
 
      return FALSE;
236
 
   }
237
 
 
238
 
   diffSecs = hostSecs - guestSecs;
239
 
   diffUsecs = hostUsecs - guestUsecs;
240
 
   if (diffUsecs < 0) {
241
 
      diffSecs -= 1;
242
 
      diffUsecs += 1000000U;
243
 
   }
244
 
   diff = diffSecs * 1000000L + diffUsecs;
245
 
 
246
 
#ifdef VMX86_DEBUG
247
 
   Debug("Daemon: Guest clock lost %.6f secs; limit=%.2f; "
248
 
         "%"FMT64"d secs since last update\n",
249
 
         diff / 1000000.0, maxTimeLag / 1000000.0, hostSecs - lastHostSecs);
250
 
   Debug("Daemon: %d, %d, %"FMT64"d, %"FMT64"d, %"FMT64"d.\n",
251
 
         syncOnce, slewCorrection, diff, maxTimeLag, interruptLag);
252
 
   lastHostSecs = hostSecs;
253
 
#endif
254
 
 
255
 
   if (syncOnce) {
256
 
      /*
257
 
       * Non-loop behavior:
258
 
       *
259
 
       * Perform a step correction if:
260
 
       * 1) The guest OS is behind the host OS by more than maxTimeLag + interruptLag.
261
 
       * 2) The guest OS is ahead of the host OS.
262
 
       */
263
 
      if (diff > maxTimeLag + interruptLag) {
264
 
         System_DisableTimeSlew();
265
 
         if (!System_AddToCurrentTime(diffSecs, diffUsecs)) {
266
 
            Warning("Unable to set the guest OS time: %s.\n\n", Msg_ErrString());
267
 
            return FALSE;
268
 
         }
269
 
      }
270
 
   } else {
271
 
 
272
 
      /*
273
 
       * Loop behavior:
274
 
       *
275
 
       * If guest is behind host by more than maxTimeLag + interruptLag
276
 
       * perform a step correction to the guest clock and ask the monitor
277
 
       * to drop its accumulated catchup (interruptLag).
278
 
       *
279
 
       * Otherwise, perform a slew correction.  Adjust the guest's clock
280
 
       * rate to be either faster or slower than nominal real time, such
281
 
       * that we expect to correct correctionPercent percent of the error
282
 
       * during this synchronization cycle.
283
 
       */
284
 
 
285
 
      if (diff > maxTimeLag + interruptLag) {
286
 
         System_DisableTimeSlew();
287
 
         if (!System_AddToCurrentTime(diffSecs, diffUsecs)) {
288
 
            Warning("Unable to set the guest OS time: %s.\n\n", Msg_ErrString());
289
 
            return FALSE;
290
 
         }
291
 
      } else if (slewCorrection && timeLagCall) {
292
 
         int64 slewDiff;
293
 
 
294
 
         /* Don't consider interruptLag during clock slewing. */
295
 
         slewDiff = diff - interruptLag;
296
 
 
297
 
         /* Correct only data->slewPercentCorrection percent error. */
298
 
         slewDiff = (data->slewPercentCorrection * slewDiff) / 100;
299
 
 
300
 
         if (!System_EnableTimeSlew(slewDiff, data->timeSyncPeriod)) {
301
 
            Warning("Unable to slew the guest OS time: %s.\n\n", Msg_ErrString());
302
 
            return FALSE;
303
 
         }
304
 
      } else {
305
 
         System_DisableTimeSlew();
306
 
      }
307
 
   }
308
 
 
309
 
#ifdef VMX86_DEBUG
310
 
      System_GetCurrentTime(&secs2, &usecs2);
311
 
 
312
 
      Debug("Time changed from %"FMT64"d.%"FMT64"d -> %"FMT64"d.%"FMT64"d\n",
313
 
            secs1, usecs1, secs2, usecs2);
314
 
#endif
315
 
 
316
 
   /*
317
 
    * If we have stepped the time, ask TimeTracker to reset to normal the rate
318
 
    * of timer interrupts it forwards from the host to the guest.
319
 
    */
320
 
   if (!System_IsTimeSlewEnabled()) {
321
 
      bp.in.cx.halfs.low = BDOOR_CMD_STOPCATCHUP;
322
 
      Backdoor(&bp);
323
 
   }
324
 
 
325
 
   return TRUE;
326
 
}
327
 
 
328
 
 
329
 
/*
330
 
 *-----------------------------------------------------------------------------
331
 
 *
332
 
 * ToolsDaemonConfFileLoop --
333
 
 *
334
 
 *    Run the "conf file reload" loop
335
 
 *
336
 
 * Return value:
337
 
 *    TRUE on success
338
 
 *    FALSE on failure (detail is displayed)
339
 
 *
340
 
 * Side effects:
341
 
 *    None
342
 
 *
343
 
 *-----------------------------------------------------------------------------
344
 
 */
345
 
 
346
 
static Bool
347
 
ToolsDaemonConfFileLoop(void *clientData) // IN
348
 
{
349
 
   GuestApp_Dict **pConfDict = (GuestApp_Dict **) clientData;
350
 
 
351
 
   ASSERT(pConfDict);
352
 
 
353
 
   /*
354
 
    * With the addition of the Sync Driver we can get into a state
355
 
    * where the system drive is frozen, preventing the completion of
356
 
    * any disk-based I/O. The event that periodically reloads the conf
357
 
    * file then gets blocked, which blocks the main daemon thread and
358
 
    * prevents any further GuestRPC messages from getting
359
 
    * processed. This effectively deadlocks the tools daemon and among
360
 
    * other things makes it impossible to thaw disk I/O once it's been
361
 
    * frozen.
362
 
    *
363
 
    * So, we keep track of when the disks are frozen and skip doing disk
364
 
    * I/O during that time.
365
 
    */
366
 
#if !defined(N_PLAT_NLM)
367
 
   if (!SyncDriver_DrivesAreFrozen()) {
368
 
      if (Conf_ReloadFile(pConfDict)) {
369
 
         GuestInfoServer_DisableDiskInfoQuery(
370
 
            GuestApp_GetDictEntryBool(*pConfDict, CONFNAME_DISABLEQUERYDISKINFO));
371
 
 
372
 
         Debug_Set(GuestApp_GetDictEntryBool(*pConfDict, CONFNAME_LOG),
373
 
                   DEBUG_PREFIX);
374
 
         Debug_EnableToFile(GuestApp_GetDictEntry(*pConfDict, CONFNAME_LOGFILE),
375
 
                            FALSE);
376
 
      }
377
 
   }
378
 
#else
379
 
   if (Conf_ReloadFile(pConfDict)) {
380
 
      Debug_Set(GuestApp_GetDictEntryBool(*pConfDict, CONFNAME_LOG),
381
 
                DEBUG_PREFIX);
382
 
      Debug_EnableToFile(GuestApp_GetDictEntry(*pConfDict, CONFNAME_LOGFILE),
383
 
                         FALSE);
384
 
   }
385
 
#endif
386
 
 
387
 
   EventManager_Add(ToolsDaemonEventQueue, CONF_POLL_TIME, ToolsDaemonConfFileLoop,
388
 
                    pConfDict);
389
 
   return TRUE;
390
 
}
391
 
 
392
 
 
393
 
/*
394
 
 *-----------------------------------------------------------------------------
395
 
 *
396
 
 * ToolsDaemonTimeSyncLoop --
397
 
 *
398
 
 *    Run the "time synchronization" loop
399
 
 *
400
 
 * Return value:
401
 
 *    TRUE on success
402
 
 *    FALSE on failure (detail is displayed)
403
 
 *
404
 
 * Side effects:
405
 
 *    None
406
 
 *
407
 
 *-----------------------------------------------------------------------------
408
 
 */
409
 
 
410
 
static Bool
411
 
ToolsDaemonTimeSyncLoop(void *clientData) // IN
412
 
{
413
 
   ToolsDaemon_Data *data = (ToolsDaemon_Data *)clientData;
414
 
 
415
 
   ASSERT(data);
416
 
 
417
 
   /* The event has fired: it is no longer valid */
418
 
   data->timeSyncEvent = NULL;
419
 
 
420
 
   if (!data->timeSyncPeriod) {
421
 
      data->timeSyncPeriod = TIME_SYNC_TIME;
422
 
   }
423
 
   if (!ToolsDaemon_SyncTime(data->slewCorrection, FALSE, clientData)) {
424
 
      Warning("Unable to synchronize time.\n\n");
425
 
      return FALSE;
426
 
   }
427
 
 
428
 
   data->timeSyncEvent = EventManager_Add(ToolsDaemonEventQueue, data->timeSyncPeriod,
429
 
                                          ToolsDaemonTimeSyncLoop, data);
430
 
   if (data->timeSyncEvent == NULL) {
431
 
      Warning("Unable to run the \"time synchronization\" loop.\n\n");
432
 
 
433
 
      return FALSE;
434
 
   }
435
 
 
436
 
   return TRUE;
437
 
}
438
 
 
439
 
 
440
 
/*
441
 
 *-----------------------------------------------------------------------------
442
 
 *
443
 
 * ToolsDaemonDisableWinTimeDaemon --
444
 
 *
445
 
 *      Try to disable the Windows Time Daemon.
446
 
 *
447
 
 * Results:
448
 
 *      TRUE on success
449
 
 *      FALSE on failure
450
 
 *
451
 
 * Side effects:
452
 
 *      None
453
 
 *
454
 
 *-----------------------------------------------------------------------------
455
 
 */
456
 
 
457
 
#if defined(_WIN32)
458
 
static Bool
459
 
ToolsDaemonDisableWinTimeDaemon(void)
460
 
{
461
 
   DWORD timeAdjustment;
462
 
   DWORD timeIncrement;
463
 
   DWORD error;
464
 
   BOOL timeAdjustmentDisabled;
465
 
   BOOL success = FALSE;
466
 
 
467
 
   /*
468
 
    * We need the SE_SYSTEMTIME_NAME privilege to make the change; get
469
 
    * the privilege now (or bail if we can't).
470
 
    */
471
 
   success = System_SetProcessPrivilege(SE_SYSTEMTIME_NAME, TRUE);
472
 
   if (!success) {
473
 
      return FALSE;
474
 
   }
475
 
 
476
 
   /* Actually try to stop the time daemon. */
477
 
   if (GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement,
478
 
                               &timeAdjustmentDisabled)) {
479
 
      Debug("GetSystemTimeAdjustment() succeeded: timeAdjustment %d,"
480
 
            "timeIncrement %d, timeAdjustmentDisabled %s\n",
481
 
            timeAdjustment, timeIncrement,
482
 
            timeAdjustmentDisabled ? "TRUE" : "FALSE");
483
 
      /*
484
 
       * timeAdjustmentDisabled means the opposite of what you'd think;
485
 
       * if it's TRUE, that means the system may be adjusting the time
486
 
       * on its own using the time daemon. Read MSDN for the details,
487
 
       * and see Bug 24173 for more discussion on this.
488
 
       */
489
 
 
490
 
      if (timeAdjustmentDisabled) {
491
 
         /*
492
 
          * MSDN is a bit vague on the semantics of this function, but it
493
 
          * would appear that the timeAdjustment value here is simply the
494
 
          * total amount that the system will add to the clock on each
495
 
          * timer tick, i.e. if you set it to zero the system clock will
496
 
          * not progress at all (and indeed, attempting to set it to zero
497
 
          * results in an ERROR_INVALID_PARAMETER). In order to have time
498
 
          * proceed at the normal rate, this needs to be set to the value
499
 
          * of timeIncrement retrieved from GetSystemTimeAdjustment().
500
 
          */
501
 
         if (!SetSystemTimeAdjustment(timeIncrement, FALSE)) {
502
 
            error = GetLastError();
503
 
            Debug("Daemon: SetSystemTimeAdjustment failed: %d\n", error);
504
 
            goto exit;
505
 
         }
506
 
      }
507
 
   } else {
508
 
      error = GetLastError();
509
 
      Debug("Daemon: GetSystemTimeAdjustment failed: %d\n", error);
510
 
      goto exit;
511
 
   }
512
 
 
513
 
   success = TRUE;
514
 
 
515
 
  exit:
516
 
   Debug("Stopping time daemon %s.\n", success ? "succeeded" : "failed");
517
 
   System_SetProcessPrivilege(SE_SYSTEMTIME_NAME, FALSE);
518
 
   return success;
519
 
}
520
 
#endif
521
 
 
522
 
 
523
 
/*
524
 
 *-----------------------------------------------------------------------------
525
 
 *
526
 
 * ToolsDaemonStartStopTimeSyncLoop --
527
 
 *
528
 
 *    Start or stop the "time synchronization" loop. Nothing will be
529
 
 *    done if start==TRUE & it's already running or start=FALSE & it's
530
 
 *    not running.
531
 
 *
532
 
 * Return value:
533
 
 *    TRUE on success
534
 
 *    FALSE on failure (detail is displayed)
535
 
 *
536
 
 * Side effects:
537
 
 *    None
538
 
 *
539
 
 *-----------------------------------------------------------------------------
540
 
 */
541
 
 
542
 
static Bool
543
 
ToolsDaemonStartStopTimeSyncLoop(ToolsDaemon_Data *data, // IN
544
 
                                 Bool start)             // IN
545
 
{
546
 
   ASSERT(data);
547
 
 
548
 
   if (start && data->timeSyncEvent == NULL) {
549
 
      Debug("Daemon: Starting time sync loop\n");
550
 
      Debug("Daemon: New sync period is %d sec\n", data->timeSyncPeriod);
551
 
      if (!ToolsDaemonTimeSyncLoop(data)) {
552
 
         return FALSE;
553
 
      }
554
 
 
555
 
#if defined(_WIN32)
556
 
      Debug("Daemon: Attempting to disable Windows Time daemon\n");
557
 
      if (!ToolsDaemonDisableWinTimeDaemon()) {
558
 
         Debug("Daemon: Failed to disable Windows Time daemon\n");
559
 
      }
560
 
#endif
561
 
 
562
 
      return TRUE;
563
 
   } else if (!start && data->timeSyncEvent != NULL) {
564
 
      Debug("Daemon: Stopping time sync loop\n");
565
 
      System_DisableTimeSlew();
566
 
      EventManager_Remove(data->timeSyncEvent);
567
 
      data->timeSyncEvent = NULL;
568
 
 
569
 
      return TRUE;
570
 
   } else {
571
 
      /*
572
 
       * No need to start time sync b/c it's already running or no
573
 
       * need to stop it b/c it's not running.
574
 
       */
575
 
      return TRUE;
576
 
   }
577
 
}
578
 
 
579
 
 
580
 
/*
581
 
 *-----------------------------------------------------------------------------
582
 
 *
583
 
 * ToolsDaemonOldUpdateOptions --
584
 
 *
585
 
 *    Get the latest value of the tools options from VMware, and update
586
 
 *    guestd's behavior according to this new value
587
 
 *    (Legacy from before the unified TCLO loop)
588
 
 *
589
 
 * Return value:
590
 
 *    TRUE on success
591
 
 *    FALSE on failure (detail is displayed)
592
 
 *
593
 
 * Side effects:
594
 
 *    None
595
 
 *
596
 
 *-----------------------------------------------------------------------------
597
 
 */
598
 
 
599
 
static Bool
600
 
ToolsDaemonOldUpdateOptions(ToolsDaemon_Data *data) // IN
601
 
{
602
 
   uint32 toolsOptions;
603
 
   Bool syncTime;
604
 
   Bool copyPaste;
605
 
   Bool autoHide;
606
 
 
607
 
   ASSERT(data);
608
 
 
609
 
   toolsOptions = GuestApp_OldGetOptions();
610
 
 
611
 
   syncTime = (toolsOptions & VMWARE_GUI_SYNC_TIME) != 0;
612
 
   GuestApp_SetDictEntry(data->optionsDict, TOOLSOPTION_SYNCTIME,
613
 
                           syncTime ? "1" : "0");
614
 
   copyPaste = (toolsOptions & VMWARE_GUI_EXCHANGE_SELECTIONS) != 0;
615
 
   GuestApp_SetDictEntry(data->optionsDict, TOOLSOPTION_COPYPASTE,
616
 
                           copyPaste ? "1" : "0");
617
 
   autoHide = (toolsOptions & VMWARE_GUI_WARP_CURSOR_ON_UNGRAB) != 0;
618
 
   GuestApp_SetDictEntry(data->optionsDict, TOOLSOPTION_AUTOHIDE,
619
 
                           autoHide ? "1" : "0");
620
 
 
621
 
   if (ToolsDaemonStartStopTimeSyncLoop(data, syncTime) == FALSE) {
622
 
      return FALSE;
623
 
   }
624
 
 
625
 
   return TRUE;
626
 
}
627
 
 
628
 
 
629
 
/*
630
 
 *-----------------------------------------------------------------------------
631
 
 *
632
 
 * ToolsDaemonOldUpdateOptionsLoop --
633
 
 *
634
 
 *    Run the "update options" loop
635
 
 *    (Legacy from before the unified TCLO loop)
636
 
 *
637
 
 * Return value:
638
 
 *    TRUE on success
639
 
 *    FALSE on failure (detail is displayed)
640
 
 *
641
 
 * Side effects:
642
 
 *    None
643
 
 *
644
 
 *-----------------------------------------------------------------------------
645
 
 */
646
 
 
647
 
static Bool
648
 
ToolsDaemonOldUpdateOptionsLoop(void *clientData) // IN
649
 
{
650
 
   ToolsDaemon_Data *data = (ToolsDaemon_Data *)clientData;
651
 
 
652
 
   ASSERT(data);
653
 
 
654
 
   if (ToolsDaemonOldUpdateOptions(data) == FALSE) {
655
 
      return FALSE;
656
 
   }
657
 
 
658
 
   data->oldOptionsLoop = EventManager_Add(ToolsDaemonEventQueue, 100,
659
 
                                           ToolsDaemonOldUpdateOptionsLoop, data);
660
 
   if (data->oldOptionsLoop == NULL) {
661
 
      Warning("Unable to run the \"update options\" loop.\n");
662
 
      return FALSE;
663
 
   }
664
 
 
665
 
   return TRUE;
666
 
}
667
 
 
668
 
 
669
 
/*
670
 
 *-----------------------------------------------------------------------------
671
 
 *
672
 
 * ToolsDaemonStartStopOldUpdateOptionsLoop --
673
 
 *
674
 
 *      Start or stop the old upate options loop depending
675
 
 *      on whether vmware is unified loop capable.
676
 
 *      It won't be started again it's already running & it won't be
677
 
 *      stopped if it's not running.
678
 
 *
679
 
 * Results:
680
 
 *      TRUE on success
681
 
 *      FALSE if all attempts to get options have failed.
682
 
 *
683
 
 * Side effects:
684
 
 *      None
685
 
 *
686
 
 *-----------------------------------------------------------------------------
687
 
 */
688
 
 
689
 
static Bool
690
 
ToolsDaemonStartStopOldUpdateOptionsLoop(ToolsDaemon_Data *data) // IN
691
 
{
692
 
   Bool unifiedLoopCap;
693
 
 
694
 
   ASSERT(data);
695
 
 
696
 
   /*
697
 
    * Start the old options loop if it's not running & the unified loop is no
698
 
    * supported; stop it if it is running & the unified loop is supported.
699
 
    */
700
 
   unifiedLoopCap = GuestApp_GetUnifiedLoopCap(TOOLS_DAEMON_NAME);
701
 
   if (!unifiedLoopCap && data->oldOptionsLoop == NULL) {
702
 
      Debug("Daemon: No unified loop cap; starting old poll loop.\n");
703
 
 
704
 
      if (!ToolsDaemonOldUpdateOptionsLoop(data)) {
705
 
         return FALSE;
706
 
      }
707
 
   } else if (unifiedLoopCap && data->oldOptionsLoop != NULL) {
708
 
      Debug("Daemon: Unified loop cap found; stopping old poll loop.\n");
709
 
 
710
 
      EventManager_Remove(data->oldOptionsLoop);
711
 
      data->oldOptionsLoop = NULL;
712
 
   } else {
713
 
      /*
714
 
       * No need to start the loop b/c it's already running or no
715
 
       * need to stop it b/c it's not running.
716
 
       */
717
 
   }
718
 
 
719
 
   return TRUE;
720
 
}
721
 
 
722
 
 
723
 
/*
724
 
 *-----------------------------------------------------------------------------
725
 
 *
726
 
 * ToolsDaemonResetSent --
727
 
 *
728
 
 *      Called after we've sent the reset TCLO completion to vmware.
729
 
 *
730
 
 * Results:
731
 
 *      TRUE on success
732
 
 *      FALSE on failure
733
 
 *
734
 
 * Side effects:
735
 
 *      Set our version in vmware & start/stop the old options loop.
736
 
 *
737
 
 *-----------------------------------------------------------------------------
738
 
 */
739
 
 
740
 
static Bool
741
 
ToolsDaemonResetSent(void *clientData) // IN
742
 
{
743
 
   ToolsDaemon_Data *data = (ToolsDaemon_Data *)clientData;
744
 
 
745
 
   ASSERT(data);
746
 
 
747
 
#if !defined(N_PLAT_NLM)
748
 
   GuestInfoServer_VMResumedNotify();
749
 
#endif
750
 
 
751
 
   GuestApp_Log("Version: " BUILD_NUMBER "\n");
752
 
 
753
 
   if (!ToolsDaemonStartStopOldUpdateOptionsLoop(data)) {
754
 
      /* We aren't much use if we can't get the options */
755
 
      Panic("Unable to get options from %s\n", PRODUCT_LINE_NAME);
756
 
   }
757
 
 
758
 
   if (data->resetCB) {
759
 
      data->resetCB(data->resetCBData);
760
 
   }
761
 
 
762
 
   return TRUE;
763
 
}
764
 
 
765
 
 
766
 
/*
767
 
 *-----------------------------------------------------------------------------
768
 
 *
769
 
 * ToolsDaemonTcloReset --
770
 
 *
771
 
 *      'reset' tclo cmd handler. MUST be the first tclo message sent
772
 
 *      by VMware when it recognizes that a toolbox app has opened
773
 
 *      a tclo channel.
774
 
 *
775
 
 * Results:
776
 
 *      TRUE on success (*result is empty)
777
 
 *      FALSE on failure (*result contains the error)
778
 
 *
779
 
 * Side effects:
780
 
 *      May start or stop the old update options loop.
781
 
 *
782
 
 *-----------------------------------------------------------------------------
783
 
 */
784
 
 
785
 
static Bool
786
 
ToolsDaemonTcloReset(RpcInData *data)  // IN/OUT
787
 
{
788
 
   /*
789
 
    * Mandatory reset RPC
790
 
    */
791
 
 
792
 
   Debug("----------Daemon: Received 'reset' from vmware\n");
793
 
 
794
 
   /*
795
 
    * Schedule the post-reset actions to happen a little after one cycle of the
796
 
    * RpcIn loop. This will give vmware a chance to receive the ATR &
797
 
    * reinitialize the channel if appropriate. [greg]
798
 
    */
799
 
   EventManager_Add(ToolsDaemonEventQueue, (int) (RPCIN_POLL_TIME * 1.5),
800
 
                    ToolsDaemonResetSent, data->clientData);
801
 
 
802
 
   return RPCIN_SETRETVALS(data, "ATR " TOOLS_DAEMON_NAME, TRUE);
803
 
}
804
 
 
805
 
 
806
 
/*
807
 
 *-----------------------------------------------------------------------------
808
 
 *
809
 
 * ToolsDaemonStateChangeDone --
810
 
 *
811
 
 *      Called when a state change script is done running.
812
 
 *      Sends the state change status with the script exit value.
813
 
 *
814
 
 * Results:
815
 
 *      None
816
 
 *
817
 
 * Side effects:
818
 
 *      May halt/reboot the VM. Also VMware may suspend the VM upon
819
 
 *      receipt of a positive status.
820
 
 *
821
 
 *-----------------------------------------------------------------------------
822
 
 */
823
 
 
824
 
static void
825
 
ToolsDaemonStateChangeDone(Bool status,  // IN
826
 
                           void *cbData) // IN
827
 
{
828
 
   ToolsDaemon_Data *data = (ToolsDaemon_Data *) cbData;
829
 
 
830
 
   ASSERT(data);
831
 
   ASSERT(data->rebootCB);
832
 
   ASSERT(data->haltCB);
833
 
 
834
 
   Debug("Daemon: state change callback called\n");
835
 
 
836
 
   /*
837
 
    * We execute the requested action if the script succeeded, or if the
838
 
    * same action was tried before but didn't finish due to a script failure.
839
 
    * See bug 168568 for discussion.
840
 
    */
841
 
   if (status || data->lastFailedStateChg == data->stateChgInProgress) {
842
 
      status = TRUE;
843
 
#ifdef _WIN32
844
 
      if (data->stateChgInProgress == GUESTOS_STATECHANGE_REBOOT || data->stateChgInProgress == GUESTOS_STATECHANGE_HALT) {
845
 
         if (Hostinfo_GetOSType() >= OS_VISTA) {
846
 
            DISABLE_RES_CAPS();
847
 
         }
848
 
      }
849
 
#endif
850
 
      if (data->stateChgInProgress == GUESTOS_STATECHANGE_REBOOT) {
851
 
         Debug("Initiating reboot\n");
852
 
         status = data->rebootCB(data->rebootCBData);
853
 
      } else if (data->stateChgInProgress == GUESTOS_STATECHANGE_HALT) {
854
 
         Debug("Initiating halt\n");
855
 
         status = data->haltCB(data->haltCBData);
856
 
      }
857
 
      data->lastFailedStateChg = GUESTOS_STATECHANGE_NONE;
858
 
   }
859
 
 
860
 
   if (!status) {
861
 
      data->lastFailedStateChg = data->stateChgInProgress;
862
 
   }
863
 
 
864
 
   if (!ToolsDaemon_SetOsPhase(status, data->stateChgInProgress)) {
865
 
      Warning("Unable to send the status RPCI");
866
 
   }
867
 
 
868
 
   data->stateChgInProgress = GUESTOS_STATECHANGE_NONE;
869
 
 
870
 
   /* Unless the process couldn't be spawned, we need to free it */
871
 
   if (data->asyncProc) {
872
 
      free(data->asyncProc);
873
 
      data->asyncProc = NULL;
874
 
   }
875
 
}
876
 
 
877
 
 
878
 
/*
879
 
 * Bug 294328:  Mac OS guests do not (yet) support the state change RPCs.
880
 
 */
881
 
#ifndef __APPLE__
882
 
/*
883
 
 *-----------------------------------------------------------------------------
884
 
 *
885
 
 * ToolsDaemonTcloStateChange --
886
 
 *
887
 
 *      Tclo cmd handler for commands which invoke state change scripts.
888
 
 *
889
 
 * Results:
890
 
 *      TRUE on success (*result is empty)
891
 
 *      FALSE on failure (*result contains the error)
892
 
 *
893
 
 * Side effects:
894
 
 *      Scripts are invoked in the guest.
895
 
 *
896
 
 *-----------------------------------------------------------------------------
897
 
 */
898
 
 
899
 
static Bool
900
 
ToolsDaemonTcloStateChange(char const **result,     // OUT
901
 
                           size_t *resultLen,       // OUT
902
 
                           const char *name,        // IN
903
 
                           const char *args,        // IN
904
 
                           size_t argsSize,         // Ignored
905
 
                           void *clientData)        // IN
906
 
{
907
 
   int i;
908
 
   ProcMgr_ProcArgs procArgs;
909
 
   ToolsDaemon_Data *data = (ToolsDaemon_Data *)clientData;
910
 
 
911
 
   ASSERT(data);
912
 
   ASSERT(data->pConfDict);
913
 
   ASSERT(*data->pConfDict);
914
 
 
915
 
   Debug("Got state change message\n");
916
 
 
917
 
   if (data->asyncProc != NULL) {
918
 
      Debug("State change already in progress\n");
919
 
      return RpcIn_SetRetVals(result, resultLen,
920
 
                              "State change already in progress", FALSE);
921
 
   }
922
 
 
923
 
   for (i = 0; i < ARRAYSIZE(stateChangeCmdTable); i++) {
924
 
      if (strcmp(name, stateChangeCmdTable[i].tcloCmd) == 0) {
925
 
         char *script;
926
 
         char *scriptCmd;
927
 
         unsigned int stateId;
928
 
 
929
 
         stateId = stateChangeCmdTable[i].id;
930
 
         data->stateChgInProgress = (GuestOsState)stateId;
931
 
 
932
 
         /* Check for the toolScripts option. */
933
 
         if (!data->toolScriptOption[stateId]) {
934
 
            ToolsDaemonStateChangeDone(TRUE, data);
935
 
            Debug("Script for %s not configured to run\n", stateChangeCmdTable[i].tcloCmd);
936
 
            return RpcIn_SetRetVals(result, resultLen, "", TRUE);
937
 
         }
938
 
 
939
 
         script = Util_SafeStrdup(GuestApp_GetDictEntry(*data->pConfDict,
940
 
                                                        stateChgConfNames[stateId]));
941
 
         Debug("Script to execute is: %s\n", script);
942
 
         if (strlen(script) == 0) {
943
 
            ToolsDaemonStateChangeDone(TRUE, data);
944
 
            Debug("No script to run\n");
945
 
            free(script);
946
 
            return RpcIn_SetRetVals(result, resultLen, "", TRUE);
947
 
         } else if (!Util_IsAbsolutePath(script)) {
948
 
            char *absScript;
949
 
            char *installDir = GuestApp_GetInstallPath();
950
 
            ASSERT_MEM_ALLOC(installDir);
951
 
            absScript = Str_Asprintf(NULL, "%s%c%s", installDir, DIRSEPC, script);
952
 
            ASSERT_MEM_ALLOC(absScript);
953
 
            free(script);
954
 
            script = absScript;
955
 
         }
956
 
#ifdef N_PLAT_NLM
957
 
         procArgs = NULL;
958
 
         scriptCmd = Str_Asprintf(NULL, "%s", script);
959
 
#elif !defined(_WIN32)
960
 
         procArgs = NULL;
961
 
         ASSERT(data->execLogPath);
962
 
         scriptCmd = Str_Asprintf(NULL, "(%s) 2>&1 >> %s",
963
 
                                  script, data->execLogPath);
964
 
#else
965
 
         /*
966
 
          * Pass the CREATE_NO_WINDOW flag to CreateProcess so that the
967
 
          * cmd.exe window will not be visible to the user in the guest.
968
 
          */
969
 
         memset(&procArgs, 0, sizeof procArgs);
970
 
         procArgs.bInheritHandles = TRUE;
971
 
         procArgs.dwCreationFlags = CREATE_NO_WINDOW;
972
 
 
973
 
         {
974
 
            char systemDir[1024 * 3];
975
 
            Win32U_GetSystemDirectory(systemDir, sizeof systemDir);
976
 
            scriptCmd = Str_Asprintf(NULL, "%s\\cmd.exe /c \"%s\"", systemDir, script);
977
 
         }
978
 
#endif
979
 
 
980
 
         if (scriptCmd == NULL) {
981
 
            Debug("Could not format the cmd to run scripts\n");
982
 
            return RpcIn_SetRetVals(result, resultLen,
983
 
                                    "Could not format cmd to run scritps",
984
 
                                    FALSE);
985
 
         }
986
 
         data->asyncProc = ProcMgr_ExecAsync(scriptCmd, &procArgs);
987
 
 
988
 
         if (data->asyncProc) {
989
 
            data->asyncProcCb = ToolsDaemonStateChangeDone;
990
 
            data->asyncProcCbData = data;
991
 
         } else {
992
 
            ToolsDaemonStateChangeDone(FALSE, data);
993
 
            goto startError;
994
 
         }
995
 
 
996
 
         free(script);
997
 
         free(scriptCmd);
998
 
         return RpcIn_SetRetVals(result, resultLen, "", TRUE);
999
 
 
1000
 
      startError:
1001
 
         free(script);
1002
 
         free(scriptCmd);
1003
 
         Debug("Error starting script\n");   
1004
 
         return RpcIn_SetRetVals(result, resultLen, "Error starting script",
1005
 
                                 FALSE);
1006
 
      }
1007
 
   }
1008
 
 
1009
 
   Debug("Invalid state change command\n");   
1010
 
   return RpcIn_SetRetVals(result, resultLen, "Invalid state change command",
1011
 
                           FALSE);
1012
 
}
1013
 
#endif // ifndef __APPLE__
1014
 
 
1015
 
 
1016
 
/*
1017
 
 *-----------------------------------------------------------------------------
1018
 
 *
1019
 
 * ToolsDaemonTcloCapReg --
1020
 
 *
1021
 
 *    Register our capabilities with the VMX & request
1022
 
 *
1023
 
 * Return value:
1024
 
 *    TRUE on success
1025
 
 *    FALSE on failure
1026
 
 *
1027
 
 * Side effects:
1028
 
 *    None
1029
 
 *
1030
 
 *-----------------------------------------------------------------------------
1031
 
 */
1032
 
 
1033
 
static Bool
1034
 
ToolsDaemonTcloCapReg(char const **result,     // OUT
1035
 
                      size_t *resultLen,       // OUT
1036
 
                      const char *name,        // IN
1037
 
                      const char *args,        // IN
1038
 
                      size_t argsSize,         // Ignored
1039
 
                      void *clientData)        // IN
1040
 
{
1041
 
#ifdef _WIN32
1042
 
   unsigned int minResolutionWidth;
1043
 
   unsigned int minResolutionHeight;
1044
 
#endif
1045
 
   ToolsDaemon_Data *data;
1046
 
   uint32 version;
1047
 
 
1048
 
   data = (ToolsDaemon_Data *)clientData;
1049
 
   ASSERT(data);
1050
 
 
1051
 
#ifdef _WIN32
1052
 
   /*
1053
 
    * Inform the VMX that we support setting the guest
1054
 
    * resolution and display topology. Currently, this only
1055
 
    * applies on windows.
1056
 
    */
1057
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.resolution_set 1")) {
1058
 
      Debug("ToolsDaemonTcloCapReg: Unable to register resolution set capability\n");
1059
 
   }
1060
 
   /* Tell the VMX to send resolution updates to the tools daemon */
1061
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.resolution_server %s 1",
1062
 
                       TOOLS_DAEMON_NAME)) {
1063
 
      Debug("ToolsDaemonTcloCapReg: Unable to register resolution server capability\n");
1064
 
   }
1065
 
   /*
1066
 
    * Bug 149541: Windows 2000 does not currently support multimon.
1067
 
    *
1068
 
    * In addition, NT will never support multimon.  9x guests have
1069
 
    * frozen tools, and will report this capability set to 1, which
1070
 
    * current UIs will treat as unsupported.
1071
 
    */
1072
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.display_topology_set %s",
1073
 
                       Hostinfo_GetOSType() >= OS_WINXP ? "2" : "0")) {
1074
 
      Debug("ToolsDaemonTcloCapReg: Unable to register display topology set "
1075
 
            "capability\n");
1076
 
   }
1077
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.display_global_offset 1")) {
1078
 
      Debug("ToolsDaemonTcloCapReg: Unable to register display global offset "
1079
 
            "capability\n");
1080
 
   }
1081
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.color_depth_set 1")) {
1082
 
      Debug("ToolsDaemonTcloCapReg: Unable to register color depth set "
1083
 
            "capability\n");
1084
 
   }
1085
 
 
1086
 
   /*
1087
 
    * Report to the VMX any minimum guest resolution below which we
1088
 
    * can't resize the guest. See bug 58681.
1089
 
    */
1090
 
   ToolsDaemon_GetMinResolution(*data->pConfDict, &minResolutionWidth,
1091
 
                                &minResolutionHeight);
1092
 
 
1093
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.resolution_min %u %u",
1094
 
                       minResolutionWidth, minResolutionHeight)) {
1095
 
      Debug("ToolsDaemonTcloCapReg: Unable to register minimum resolution of %ux%u\n",
1096
 
            minResolutionWidth, minResolutionHeight);
1097
 
   }
1098
 
#endif
1099
 
 
1100
 
#ifdef TOOLSDAEMON_HAS_RESOLUTION
1101
 
   Resolution_RegisterCaps();
1102
 
#endif
1103
 
 
1104
 
   /*
1105
 
    * Bug 294328:  Mac OS guests do not (yet) support the state change RPCs.
1106
 
    */
1107
 
#ifndef __APPLE__
1108
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.statechange")) {
1109
 
      Debug("ToolsDaemonTcloCapReg: VMware doesn't support tools.capability.statechange. "
1110
 
            "Trying .haltreboot\n");
1111
 
      if (!RpcOut_sendOne(NULL, NULL, "tools.capability.haltreboot")) {
1112
 
         return RpcIn_SetRetVals(result, resultLen,
1113
 
                                 "Unable to register capabilities", FALSE);
1114
 
      }
1115
 
   }
1116
 
 
1117
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.softpowerop_retry")) {
1118
 
      Debug("ToolsDaemonTcloCapReg: VMX doesn't support "
1119
 
            "tools.capability.softpowerop_retry.");
1120
 
   }
1121
 
#endif  // ifndef __APPLE__
1122
 
 
1123
 
/*
1124
 
 * This is a _WIN32 || linux check, with the additional check since linux is
1125
 
 * defined when you build the NetWare Tools.
1126
 
 */
1127
 
#if (defined(_WIN32) || defined(linux)) && !defined(N_PLAT_NLM)
1128
 
   {
1129
 
      if (!RpcOut_sendOne(NULL, NULL, "tools.capability.auto_upgrade 2")) {
1130
 
         Debug("ToolsDaemonTcloCapReg: Unable to register "
1131
 
               "auto-upgrading capability.\n");
1132
 
      }
1133
 
 
1134
 
      if (guestTempDirectory == NULL) {
1135
 
#ifdef _WIN32
1136
 
         guestTempDirectory = File_GetTmpDir(FALSE);
1137
 
#else
1138
 
         guestTempDirectory = Util_GetSafeTmpDir(FALSE);
1139
 
#endif
1140
 
      }
1141
 
 
1142
 
      if (!RpcOut_sendOne(NULL, NULL, "tools.capability.guest_temp_directory 1 %s",
1143
 
                          guestTempDirectory)) {
1144
 
         Debug("ToolsDaemonTcloCapReg: Unable to register guest temp "
1145
 
               "directory capability.\n");
1146
 
      }
1147
 
   }
1148
 
#endif
1149
 
 
1150
 
#if !defined(N_PLAT_NLM)
1151
 
   {
1152
 
      char *confPath = GuestApp_GetConfPath();
1153
 
      if (!RpcOut_sendOne(NULL, NULL, "tools.capability.guest_conf_directory %s",
1154
 
                          confPath ? confPath : "")) {
1155
 
         Debug("ToolsDaemonTcloCapReg: Unable to register guest conf "
1156
 
               "directory capability.\n");
1157
 
      }
1158
 
      free(confPath);
1159
 
   }
1160
 
 
1161
 
   /* 
1162
 
    * Send the uptime here so that the VMX can detect soft resets. This must be
1163
 
    * sent before the Tools version RPC since the version RPC handler uses the
1164
 
    * uptime to detect soft resets.
1165
 
    */
1166
 
   if (!GuestInfoServer_SendUptime()) {
1167
 
      Debug("Daemon: Error setting guest uptime during 'reset' request.\n");
1168
 
   }
1169
 
#endif
1170
 
 
1171
 
   /*
1172
 
    * Send the monolithic Tools version. Using a configuration option, users
1173
 
    * can override the Tools version such that the VMX treats the Tools as not
1174
 
    * to be managed by the VMware platform.
1175
 
    */
1176
 
#if defined(OPEN_VM_TOOLS)
1177
 
   version = TOOLS_VERSION_UNMANAGED;
1178
 
#else
1179
 
   version = GuestApp_GetDictEntryBool(*data->pConfDict,
1180
 
                                       CONFNAME_DISABLETOOLSVERSION) ?
1181
 
               TOOLS_VERSION_UNMANAGED : TOOLS_VERSION_CURRENT;
1182
 
#endif
1183
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.set.version %u", version)) {
1184
 
      Debug("Daemon: Error setting tools version during 'Capabilities_Register'"
1185
 
            "request.\n");
1186
 
   }
1187
 
 
1188
 
#if !defined(N_PLAT_NLM) && !defined(sun)
1189
 
   if (!HgfsServerManager_CapReg(TOOLS_DAEMON_NAME, TRUE)) {
1190
 
      Debug("ToolsDaemonTcloCapReg: Failed to register HGFS server capability.\n");
1191
 
   }
1192
 
#endif
1193
 
 
1194
 
#if defined(WIN32)
1195
 
   HgfsUsability_RegisterServiceCaps();
1196
 
   if (Hostinfo_GetOSType() >= OS_VISTA) {
1197
 
      ServiceHelpers_SendResolutionCaps();
1198
 
   }
1199
 
#endif
1200
 
 
1201
 
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
1202
 
}
1203
 
 
1204
 
 
1205
 
/*
1206
 
 *-----------------------------------------------------------------------------
1207
 
 *
1208
 
 * ToolsDaemonTcloTimeSync --
1209
 
 *
1210
 
 *    Sync the guest's time with the host's.
1211
 
 *
1212
 
 * Return value:
1213
 
 *    TRUE on success
1214
 
 *    FALSE on failure
1215
 
 *
1216
 
 * Side effects:
1217
 
 *    None
1218
 
 *
1219
 
 *-----------------------------------------------------------------------------
1220
 
 */
1221
 
 
1222
 
static Bool
1223
 
ToolsDaemonTcloTimeSync(char const **result,     // OUT
1224
 
                        size_t *resultLen,       // OUT
1225
 
                        const char *name,        // IN
1226
 
                        const char *args,        // IN
1227
 
                        size_t argsSize,         // Ignored
1228
 
                        void *clientData)        // Ignored
1229
 
{
1230
 
   Bool slewCorrection = !strcmp(args, "1");
1231
 
 
1232
 
   if (!ToolsDaemon_SyncTime(slewCorrection, TRUE, clientData)) {
1233
 
      return RpcIn_SetRetVals(result, resultLen,
1234
 
                              "Unable to sync time", FALSE);
1235
 
   } else {
1236
 
      return RpcIn_SetRetVals(result, resultLen, "", TRUE);
1237
 
   }
1238
 
}
1239
 
 
1240
 
 
1241
 
/*
1242
 
 *-----------------------------------------------------------------------------
1243
 
 *
1244
 
 * ToolsDaemonTcloSetOption --
1245
 
 *
1246
 
 *    Parse a "Set_Option" TCLO cmd from the VMX & update the local
1247
 
 *    value of the option.
1248
 
 *
1249
 
 * Return value:
1250
 
 *    TRUE if the set option command was executed
1251
 
 *    FALSE if something failed (detail displayed)
1252
 
 *
1253
 
 * Side effects:
1254
 
 *    Start or stop processes (like time syncing) that could be affected
1255
 
 *    by option's new value.
1256
 
 *
1257
 
 *-----------------------------------------------------------------------------
1258
 
 */
1259
 
 
1260
 
static Bool
1261
 
ToolsDaemonTcloSetOption(char const **result,     // OUT
1262
 
                         size_t *resultLen,       // OUT
1263
 
                         const char *name,        // IN
1264
 
                         const char *args,        // IN
1265
 
                         size_t argsSize,         // Ignored
1266
 
                         void *clientData)        // IN
1267
 
{
1268
 
   Bool retVal = FALSE;
1269
 
   char *option;
1270
 
   char *value;
1271
 
   unsigned int index = 0;
1272
 
   static Bool timeSyncStartup = TRUE;
1273
 
   static int oldTimeSyncValue = -1;
1274
 
 
1275
 
   ToolsDaemon_Data *data = (ToolsDaemon_Data *)clientData;
1276
 
 
1277
 
   ASSERT(data);
1278
 
 
1279
 
   /* parse the option & value string */
1280
 
   option = StrUtil_GetNextToken(&index, args, " ");
1281
 
   index++; // ignore leading space before value
1282
 
   value = StrUtil_GetNextToken(&index, args, "");
1283
 
   if (option == NULL || value == NULL || strlen(value) == 0) {
1284
 
      goto invalid_option;
1285
 
   }
1286
 
 
1287
 
   /* Validate the option name & value */
1288
 
   if (strcmp(option, TOOLSOPTION_SYNCTIME) == 0) {
1289
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1290
 
         goto invalid_value;
1291
 
      }
1292
 
   } else if (strcmp(option, TOOLSOPTION_SYNCTIME_SLEWCORRECTION) == 0) {
1293
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1294
 
         goto invalid_value;
1295
 
      }
1296
 
   } else if (strcmp(option, TOOLSOPTION_SYNCTIME_PERCENTCORRECTION) == 0) {
1297
 
      int32 percent;
1298
 
      if (!StrUtil_StrToInt(&percent, value) || percent == 0 || percent > 100) {
1299
 
         goto invalid_value;
1300
 
      }
1301
 
      Debug("Daemon: update the slew correction percent.\n");
1302
 
   } else if (strcmp(option, TOOLSOPTION_COPYPASTE) == 0) {
1303
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1304
 
         goto invalid_value;
1305
 
      }
1306
 
   } else if (strcmp(option, TOOLSOPTION_AUTOHIDE) == 0) {
1307
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1308
 
         goto invalid_value;
1309
 
      }
1310
 
   } else if (strcmp(option, TOOLSOPTION_BROADCASTIP) == 0) {
1311
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1312
 
         goto invalid_value;
1313
 
      }
1314
 
   } else if (strcmp(option, TOOLSOPTION_SYNCTIME_PERIOD) == 0) {
1315
 
      Debug("Daemon: update the time sync period.\n");
1316
 
   } else if (strcmp(option, TOOLSOPTION_SYNCTIME_ENABLE) == 0) {
1317
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1318
 
         goto invalid_value;
1319
 
      }
1320
 
   } else if (strcmp(option, TOOLSOPTION_SYNCTIME_STARTUP) == 0) {
1321
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1322
 
         goto invalid_value;
1323
 
      }
1324
 
   } else if (strcmp(option, TOOLSOPTION_LINK_ROOT_HGFS_SHARE) == 0) {
1325
 
      /*
1326
 
       * Check to make sure that we actually support creating the link
1327
 
       * on this platform.
1328
 
       */
1329
 
      if (!data->linkHgfsCB || !data->unlinkHgfsCB) {
1330
 
         goto invalid_option;
1331
 
      }
1332
 
 
1333
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1334
 
         goto invalid_value;
1335
 
      }
1336
 
   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_POWERON) == 0) {
1337
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1338
 
         goto invalid_value;
1339
 
      }
1340
 
   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_POWEROFF) == 0) {
1341
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1342
 
         goto invalid_value;
1343
 
      }
1344
 
   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_SUSPEND) == 0) {
1345
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1346
 
         goto invalid_value;
1347
 
      }
1348
 
   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_RESUME) == 0) {
1349
 
      if (strcmp(value, "1") != 0 && strcmp(value, "0") != 0) {
1350
 
         goto invalid_value;
1351
 
      }
1352
 
   } else {
1353
 
      goto invalid_option;
1354
 
   }
1355
 
 
1356
 
   Debug("Daemon: Setting option '%s' to '%s'\n", option, value);
1357
 
   GuestApp_SetDictEntry(data->optionsDict, option, value);
1358
 
 
1359
 
   /* Take action that may be necessary given the new value */
1360
 
   if (strcmp(option, TOOLSOPTION_SYNCTIME) == 0) {
1361
 
      int start = (strcmp(value, "1") == 0);
1362
 
 
1363
 
      /* 
1364
 
       * Try the one-shot time sync if time sync transitions from
1365
 
       * 'off' to 'on'.
1366
 
       */
1367
 
      if (oldTimeSyncValue == 0 && start &&
1368
 
          GuestApp_GetDictEntry(data->optionsDict, TOOLSOPTION_SYNCTIME_ENABLE)) {
1369
 
         ToolsDaemon_SyncTime(data->slewCorrection, TRUE, clientData);
1370
 
      }
1371
 
      oldTimeSyncValue = start;
1372
 
      
1373
 
      /* Now start/stop the loop. */
1374
 
      if (!ToolsDaemonStartStopTimeSyncLoop(data, start)) {
1375
 
         RpcIn_SetRetVals(result, resultLen,
1376
 
                          "Unable to start/stop time sync loop",
1377
 
                          retVal = FALSE);
1378
 
         goto exit;
1379
 
      }
1380
 
   } else if (strcmp(option, TOOLSOPTION_SYNCTIME_SLEWCORRECTION) == 0) {
1381
 
      data->slewCorrection = strcmp(value, "0");
1382
 
      Debug("Daemon: Setting slewCorrection, %d.\n", data->slewCorrection);
1383
 
   } else if (strcmp(option, TOOLSOPTION_SYNCTIME_PERCENTCORRECTION) == 0) {
1384
 
      int32 percent;
1385
 
      if (StrUtil_StrToInt(&percent, value)) {
1386
 
         data->slewPercentCorrection = percent;
1387
 
      }
1388
 
   } else if (strcmp(option, TOOLSOPTION_BROADCASTIP) == 0 &&
1389
 
              strcmp(value, "1") == 0) {
1390
 
      char *ip;
1391
 
 
1392
 
      ip = NetUtil_GetPrimaryIP();
1393
 
 
1394
 
      if (ip == NULL) {
1395
 
         RpcIn_SetRetVals(result, resultLen, "Error getting IP address of guest",
1396
 
                          retVal = FALSE);
1397
 
         RpcOut_sendOne(NULL, NULL, "info-set guestinfo.ip %s",
1398
 
                        GUESTINFO_IP_UNKNOWN);
1399
 
         goto exit;
1400
 
      }
1401
 
 
1402
 
      RpcOut_sendOne(NULL, NULL, "info-set guestinfo.ip %s",
1403
 
                     ip[0] == '\0' ? GUESTINFO_IP_UNKNOWN : ip);
1404
 
      free(ip);
1405
 
   } else if (strcmp(option, TOOLSOPTION_SYNCTIME_PERIOD) == 0) {
1406
 
      uint32 period = atoi(value);
1407
 
 
1408
 
      /*
1409
 
       * If the sync loop is running and
1410
 
       * the time sync period has changed,
1411
 
       * restart the loop with the new period value.
1412
 
       * If the sync loop is not running,
1413
 
       * just remember the new sync period value.
1414
 
       */
1415
 
      if (period != data->timeSyncPeriod) {
1416
 
         data->timeSyncPeriod = period * 100;
1417
 
 
1418
 
         if (data->timeSyncEvent != NULL) {
1419
 
            Bool status;
1420
 
 
1421
 
            /* Stop the loop. */
1422
 
            status = ToolsDaemonStartStopTimeSyncLoop(data, FALSE);
1423
 
 
1424
 
            /* Start the loop with the new period value. */
1425
 
            status = ToolsDaemonStartStopTimeSyncLoop(data, TRUE);
1426
 
 
1427
 
            if (!status) {
1428
 
               RpcIn_SetRetVals(result, resultLen,
1429
 
                                "Unable to change time sync period value",
1430
 
                                retVal = FALSE);
1431
 
               goto exit;
1432
 
            }
1433
 
         }
1434
 
      }
1435
 
   } else if (strcmp(option, TOOLSOPTION_SYNCTIME_STARTUP) == 0) {
1436
 
      uint32 syncStartupOk = atoi(value);
1437
 
 
1438
 
      if (timeSyncStartup) {
1439
 
         timeSyncStartup = FALSE;
1440
 
 
1441
 
         if (syncStartupOk) {
1442
 
            if (!ToolsDaemon_SyncTime(TRUE, TRUE, clientData)) {
1443
 
               RpcIn_SetRetVals(result, resultLen,
1444
 
                                "Unable to sync time during startup",
1445
 
                                retVal = FALSE);
1446
 
               goto exit;
1447
 
            }
1448
 
         }
1449
 
      }
1450
 
   } else if (strcmp(option, TOOLSOPTION_LINK_ROOT_HGFS_SHARE) == 0) {
1451
 
      if (strcmp(value, "1") == 0) {
1452
 
         /* Validated that data->linkHgfsCB existed above. */
1453
 
         retVal = data->linkHgfsCB(data->linkHgfsCBData);
1454
 
      } else if (strcmp(value, "0") == 0) {
1455
 
         /* Validated that data->unlinkHgfsCB existed above. */
1456
 
         retVal = data->unlinkHgfsCB(data->unlinkHgfsCBData);
1457
 
      }
1458
 
 
1459
 
      if (!retVal) {
1460
 
         RpcIn_SetRetVals(result, resultLen,
1461
 
                          "Could not link/unlink root share.",
1462
 
                          retVal = FALSE);
1463
 
         goto exit;
1464
 
      }
1465
 
   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_POWERON) == 0) {
1466
 
      data->toolScriptOption[GUESTOS_STATECHANGE_POWERON] =
1467
 
                                strcmp(value, "0") ? TRUE : FALSE;
1468
 
   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_POWEROFF) == 0) {
1469
 
      data->toolScriptOption[GUESTOS_STATECHANGE_HALT] =
1470
 
      data->toolScriptOption[GUESTOS_STATECHANGE_REBOOT] =
1471
 
                                strcmp(value, "0") ? TRUE : FALSE;
1472
 
   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_SUSPEND) == 0) {
1473
 
      data->toolScriptOption[GUESTOS_STATECHANGE_SUSPEND] =
1474
 
                                strcmp(value, "0") ? TRUE : FALSE;
1475
 
   } else if (strcmp(option, TOOLSOPTION_SCRIPTS_RESUME) == 0) {
1476
 
      data->toolScriptOption[GUESTOS_STATECHANGE_RESUME] =
1477
 
                                strcmp(value, "0") ? TRUE : FALSE;
1478
 
   }
1479
 
 
1480
 
   /* success! */
1481
 
   RpcIn_SetRetVals(result, resultLen, "", retVal = TRUE);
1482
 
   goto exit;
1483
 
 
1484
 
 invalid_option:
1485
 
   RpcIn_SetRetVals(result, resultLen, "Unknown option", retVal = FALSE);
1486
 
   goto exit;
1487
 
 
1488
 
 invalid_value:
1489
 
   RpcIn_SetRetVals(result, resultLen, "Invalid option value",
1490
 
                    retVal = FALSE);
1491
 
   goto exit;
1492
 
 
1493
 
 exit:
1494
 
   free(option);
1495
 
   free(value);
1496
 
   return retVal;
1497
 
}
1498
 
 
1499
 
 
1500
 
/*
1501
 
 *-----------------------------------------------------------------------------
1502
 
 *
1503
 
 * ToolsDaemonTcloError --
1504
 
 *
1505
 
 *    Callback called when an error occurred in the receive loop
1506
 
 *
1507
 
 * Return value:
1508
 
 *    None
1509
 
 *
1510
 
 * Side effects:
1511
 
 *    None
1512
 
 *
1513
 
 *-----------------------------------------------------------------------------
1514
 
 */
1515
 
 
1516
 
static void
1517
 
ToolsDaemonTcloError(void *clientData,   // IN
1518
 
                     char const *status) // IN
1519
 
{
1520
 
   ToolsDaemon_Data *data = (ToolsDaemon_Data *)clientData;
1521
 
 
1522
 
   ASSERT(data);
1523
 
 
1524
 
   Warning("Error in the RPC receive loop: %s.\n\n", status);
1525
 
   data->inError = TRUE;
1526
 
}
1527
 
 
1528
 
 
1529
 
/*
1530
 
 *-----------------------------------------------------------------------------
1531
 
 *
1532
 
 * ToolsDaemon_Init_Backdoor --
1533
 
 *
1534
 
 *    Initializes the backdoor to the VMX.
1535
 
 *
1536
 
 * Return value:
1537
 
 *    TRUE if successful.
1538
 
 *    FALSE otherwise.
1539
 
 *
1540
 
 * Side effects:
1541
 
 *    None
1542
 
 *
1543
 
 *-----------------------------------------------------------------------------
1544
 
 */
1545
 
 
1546
 
Bool
1547
 
ToolsDaemon_Init_Backdoor(ToolsDaemon_Data * data) // IN/OUT
1548
 
{
1549
 
   data->in = RpcIn_Construct(ToolsDaemonEventQueue);
1550
 
   if (data->in == NULL) {
1551
 
      Warning("Unable to create the RpcIn object.\n\n");
1552
 
      return FALSE;
1553
 
   }
1554
 
 
1555
 
   /*
1556
 
    * Initialize 'inError' before starting the loop -- clients should 
1557
 
    * only read this flag.
1558
 
    */
1559
 
   data->inError = FALSE;
1560
 
 
1561
 
 
1562
 
   /* Start the TCLO receive loop */
1563
 
   if (RpcIn_start(data->in, RPCIN_POLL_TIME,
1564
 
                   ToolsDaemonTcloReset, data,
1565
 
                   ToolsDaemonTcloError, data) == FALSE) {
1566
 
      RpcIn_Destruct(data->in);
1567
 
      data->in = NULL;
1568
 
      Warning("Unable to start the receive loop.\n\n");
1569
 
      return FALSE;
1570
 
   }
1571
 
 
1572
 
   RpcIn_RegisterCallback(data->in, "Time_Synchronize",
1573
 
                          ToolsDaemonTcloTimeSync, NULL);
1574
 
   RpcIn_RegisterCallback(data->in, "Capabilities_Register",
1575
 
                          ToolsDaemonTcloCapReg, data);
1576
 
   RpcIn_RegisterCallback(data->in, "Set_Option",
1577
 
                          ToolsDaemonTcloSetOption, data);
1578
 
 
1579
 
   /*
1580
 
    * Bug 294328:  Mac OS guests do not (yet) support the state change RPCs.
1581
 
    */
1582
 
#ifndef __APPLE__
1583
 
   {
1584
 
      int i;
1585
 
      for (i = 0; i < ARRAYSIZE(stateChangeCmdTable); i++) {
1586
 
         RpcIn_RegisterCallback(data->in, stateChangeCmdTable[i].tcloCmd,
1587
 
                                ToolsDaemonTcloStateChange, data);
1588
 
      }
1589
 
   }
1590
 
#endif // ifndef __APPLE__
1591
 
 
1592
 
#if !defined(N_PLAT_NLM)
1593
 
   FoundryToolsDaemon_RegisterRoutines(data->in,
1594
 
                                       data->pConfDict, 
1595
 
                                       ToolsDaemonEventQueue,
1596
 
                                       TRUE);
1597
 
   if (!HgfsServerManager_Register(data->in, TOOLS_DAEMON_NAME)) {
1598
 
      RpcIn_stop(data->in);
1599
 
      RpcIn_Destruct(data->in);
1600
 
      data->in = NULL;
1601
 
      Warning("Could not initialize HGFS server\n");
1602
 
      return FALSE;
1603
 
   }
1604
 
#endif
1605
 
 
1606
 
#ifdef TOOLSDAEMON_HAS_RESOLUTION
1607
 
   Resolution_InitBackdoor(data->in);
1608
 
#endif
1609
 
 
1610
 
#if !defined(__FreeBSD__) && !defined(sun) && !defined(N_PLAT_NLM)
1611
 
   DeployPkg_Register(data->in);
1612
 
#endif
1613
 
 
1614
 
   return TRUE;
1615
 
}
1616
 
 
1617
 
 
1618
 
/*
1619
 
 *-----------------------------------------------------------------------------
1620
 
 *
1621
 
 * ToolsDaemon_Init --
1622
 
 *
1623
 
 *    Setup a TCLO channel with VMware, and start it's event loop
1624
 
 *
1625
 
 * Return value:
1626
 
 *    the created RpcIn struct or
1627
 
 *    NULL if something failed (detail is displayed)
1628
 
 *
1629
 
 * Side effects:
1630
 
 *    None
1631
 
 *
1632
 
 *-----------------------------------------------------------------------------
1633
 
 */
1634
 
 
1635
 
ToolsDaemon_Data *
1636
 
ToolsDaemon_Init(GuestApp_Dict **pConfDict,         // IN
1637
 
                 const char *execLogPath,           // IN
1638
 
                 ToolsDaemon_Callback haltCB,       // IN
1639
 
                 void *haltCBData,                  // IN
1640
 
                 ToolsDaemon_Callback rebootCB,     // IN
1641
 
                 void *rebootCBData,                // IN
1642
 
                 ToolsDaemon_Callback resetCB,      // IN
1643
 
                 void *resetCBData,                 // IN
1644
 
                 ToolsDaemon_Callback linkHgfsCB,   // IN
1645
 
                 void *linkHgfsCBData,              // IN
1646
 
                 ToolsDaemon_Callback unlinkHgfsCB, // IN
1647
 
                 void *unlinkHgfsCBData)            // IN
1648
 
{
1649
 
   ToolsDaemon_Data *data;
1650
 
   int i;
1651
 
 
1652
 
#ifndef N_PLAT_NLM
1653
 
   Atomic_Init();
1654
 
#endif // #ifndef N_PLAT_NLM
1655
 
 
1656
 
   ASSERT(pConfDict);
1657
 
   ASSERT(*pConfDict);
1658
 
   ASSERT(haltCB != NULL);
1659
 
   ASSERT(rebootCB != NULL);
1660
 
 
1661
 
   data = (ToolsDaemon_Data *) calloc(1, sizeof(ToolsDaemon_Data));
1662
 
   ASSERT_MEM_ALLOC(data);
1663
 
 
1664
 
   data->pConfDict = pConfDict;
1665
 
   data->execLogPath = execLogPath;
1666
 
   data->inError = FALSE;
1667
 
   data->haltCB = haltCB;
1668
 
   data->haltCBData = haltCBData;
1669
 
   data->rebootCB = rebootCB;
1670
 
   data->rebootCBData = rebootCBData;
1671
 
   data->stateChgInProgress = GUESTOS_STATECHANGE_NONE;
1672
 
   data->lastFailedStateChg = GUESTOS_STATECHANGE_NONE;
1673
 
   data->resetCB = resetCB;
1674
 
   data->resetCBData = resetCBData;
1675
 
   data->linkHgfsCB = linkHgfsCB;
1676
 
   data->linkHgfsCBData = linkHgfsCBData;
1677
 
   data->unlinkHgfsCB = unlinkHgfsCB;
1678
 
   data->unlinkHgfsCBData = unlinkHgfsCBData;
1679
 
   data->timeSyncPeriod = 0;
1680
 
   data->slewPercentCorrection = PERCENT_CORRECTION;
1681
 
   data->slewCorrection = TRUE;
1682
 
 
1683
 
   for (i = 0; i < GUESTOS_STATECHANGE_LAST; i++) {
1684
 
      data->toolScriptOption[i] = TRUE;
1685
 
   }
1686
 
 
1687
 
#if ALLOW_TOOLS_IN_FOREIGN_VM
1688
 
   if (!VmCheck_IsVirtualWorld()) {
1689
 
      ToolsDaemon_InitializeForeignVM(data);
1690
 
   }
1691
 
#endif
1692
 
 
1693
 
#if defined(VMX86_DEBUG) && !defined(__APPLE__)
1694
 
   {
1695
 
      /* Make sure the confDict has all the confs we need */
1696
 
      for (i = 0; i < ARRAYSIZE(stateChangeCmdTable); i++) {
1697
 
         const char *confName;
1698
 
 
1699
 
         confName = stateChgConfNames[stateChangeCmdTable[i].id];
1700
 
         ASSERT(GuestApp_GetDictEntry(*pConfDict, confName));
1701
 
      }
1702
 
   }
1703
 
#endif
1704
 
 
1705
 
   ToolsDaemonEventQueue = EventManager_Init();
1706
 
   if(!ToolsDaemonEventQueue) {
1707
 
      Warning("Unable to create the event queue.\n\n");
1708
 
      goto error;
1709
 
   }
1710
 
 
1711
 
#ifdef TOOLSDAEMON_HAS_RESOLUTION
1712
 
   if (!Resolution_Init(TOOLS_DAEMON_NAME, NULL)) {
1713
 
      Debug("%s: Unable to initialize Guest Fit feature\n", __func__);
1714
 
   }
1715
 
#endif
1716
 
 
1717
 
   /*
1718
 
    * Load the conf file, then setup a periodic check and reload.
1719
 
    */
1720
 
   Debug_Set(GuestApp_GetDictEntryBool(*pConfDict, CONFNAME_LOG), DEBUG_PREFIX);
1721
 
 
1722
 
   /*
1723
 
    * All components except vmware-user will be logged to same file. Everytime after
1724
 
    * reboot, tools daemon should rename existing log file and start logging to a new
1725
 
    * one. In all other cases the backup flag for Debug_EnableToFile should be set to
1726
 
    * FALSE.
1727
 
    */
1728
 
   Debug_EnableToFile(GuestApp_GetDictEntry(*pConfDict, CONFNAME_LOGFILE), TRUE);
1729
 
 
1730
 
   EventManager_Add(ToolsDaemonEventQueue, CONF_POLL_TIME, ToolsDaemonConfFileLoop,
1731
 
                    data->pConfDict);
1732
 
 
1733
 
   if (!ToolsDaemon_Init_Backdoor(data)) {
1734
 
      goto error;
1735
 
   }
1736
 
 
1737
 
   data->optionsDict = GuestApp_ConstructDict(NULL);
1738
 
 
1739
 
   return data;
1740
 
 
1741
 
 error:
1742
 
   if (ToolsDaemonEventQueue) {
1743
 
      EventManager_Destroy(ToolsDaemonEventQueue);
1744
 
      ToolsDaemonEventQueue = NULL;
1745
 
   }
1746
 
   free(data);
1747
 
   return NULL;
1748
 
}
1749
 
 
1750
 
 
1751
 
/*
1752
 
 *-----------------------------------------------------------------------------
1753
 
 *
1754
 
 * ToolsDaemon_Cleanup_Backdoor --
1755
 
 *
1756
 
 *    Closes the backdoor to the VMX.
1757
 
 *
1758
 
 * Results:
1759
 
 *    None
1760
 
 *
1761
 
 * Side effects:
1762
 
 *    None
1763
 
 *
1764
 
 *-----------------------------------------------------------------------------
1765
 
 */
1766
 
 
1767
 
void
1768
 
ToolsDaemon_Cleanup_Backdoor(ToolsDaemon_Data *data) // IN/OUT
1769
 
{
1770
 
   ASSERT(data);
1771
 
   if (data->in) {
1772
 
#if !defined(N_PLAT_NLM)
1773
 
      HgfsServerManager_Unregister(data->in, TOOLS_DAEMON_NAME);
1774
 
#endif
1775
 
      RpcIn_stop(data->in);
1776
 
      RpcIn_Destruct(data->in);
1777
 
      data->in = NULL;
1778
 
   }
1779
 
}
1780
 
 
1781
 
 
1782
 
/*
1783
 
 *-----------------------------------------------------------------------------
1784
 
 *
1785
 
 * ToolsDaemon_Cleanup --
1786
 
 *
1787
 
 *    Cleanup the RpcIn channel if it hasn't been destructed yet& free the
1788
 
 *    local options.
1789
 
 *
1790
 
 * Results:
1791
 
 *    None
1792
 
 *
1793
 
 * Side effects:
1794
 
 *    None
1795
 
 *
1796
 
 *-----------------------------------------------------------------------------
1797
 
 */
1798
 
 
1799
 
void
1800
 
ToolsDaemon_Cleanup(ToolsDaemon_Data *data) // IN
1801
 
{
1802
 
#ifdef _WIN32
1803
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.resolution_set 0")) {
1804
 
      Debug("%s: Unable to unregister resolution set capability\n",
1805
 
            __FUNCTION__);
1806
 
   }
1807
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.resolution_server %s 0",
1808
 
                       TOOLS_DAEMON_NAME)) {
1809
 
      Debug("%s: Unable to unregister resolution server capability\n",
1810
 
            __FUNCTION__);
1811
 
   }
1812
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.display_topology_set 0")) {
1813
 
      Debug("%s: Unable to unregister display topology set capability\n",
1814
 
            __FUNCTION__);
1815
 
   }
1816
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.display_global_offset 0")) {
1817
 
      Debug("%s: Unable to unregister display global offset capability\n",
1818
 
            __FUNCTION__);
1819
 
   }
1820
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.color_depth_set 0")) {
1821
 
      Debug("%s: Unable to unregister color depth set capability\n",
1822
 
            __FUNCTION__);
1823
 
   }
1824
 
 
1825
 
   /*
1826
 
    * Clear the minimum resolution limitation.
1827
 
    */
1828
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.resolution_min 0 0")) {
1829
 
      Debug("%s: Unable to clear minimum resolution\n", __FUNCTION__);
1830
 
   }
1831
 
 
1832
 
   HgfsUsability_UnregisterServiceCaps();
1833
 
#endif
1834
 
 
1835
 
#ifdef TOOLSDAEMON_HAS_RESOLUTION
1836
 
   Resolution_Cleanup();
1837
 
#endif
1838
 
 
1839
 
#if defined(_WIN32) || defined(linux)
1840
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.auto_upgrade 0")) {
1841
 
      Debug("%s: Unable to clear auto-upgrading capability.\n", __FUNCTION__);
1842
 
   }
1843
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.guest_temp_directory 0")) {
1844
 
      Debug("%s: Unable to clear guest temp directory capability.\n",
1845
 
            __FUNCTION__);
1846
 
   }
1847
 
#endif
1848
 
 
1849
 
#if !defined(N_PLAT_NLM)
1850
 
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.guest_conf_directory 0")) {
1851
 
      Debug("%s: Unable to clear guest conf directory capability.\n",
1852
 
            __FUNCTION__);
1853
 
   }
1854
 
#endif
1855
 
 
1856
 
#if ALLOW_TOOLS_IN_FOREIGN_VM
1857
 
   if (runningInForeignVM) {
1858
 
      ToolsDaemon_ShutdownForeignVM();
1859
 
   }
1860
 
#endif
1861
 
 
1862
 
   ToolsDaemon_Cleanup_Backdoor(data);
1863
 
 
1864
 
   GuestApp_FreeDict(data->optionsDict);
1865
 
 
1866
 
   if (data->asyncProc) {
1867
 
      ProcMgr_Kill(data->asyncProc);
1868
 
      ToolsDaemonStateChangeDone(FALSE, data);
1869
 
   }
1870
 
 
1871
 
   EventManager_Destroy(ToolsDaemonEventQueue);
1872
 
   free(data);
1873
 
   free(guestTempDirectory);
1874
 
}
1875
 
 
1876
 
 
1877
 
/*
1878
 
 *-----------------------------------------------------------------------------
1879
 
 *
1880
 
 * ToolsDaemon_CheckReset --
1881
 
 *
1882
 
 *    Can/should be called in an app's main run loop before calling the
1883
 
 *    'sleep' function, to check and potentially reset the rpc layer.
1884
 
 *
1885
 
 * Return value:
1886
 
 *    TRUE  if no errors were encountered, or rpc re-initialization is in
1887
 
 *          progress and we haven't exceeded the maximum number of consecutive
1888
 
 *          recovery attempts
1889
 
 *    FALSE rpc can't be re-initialized, or we exhausted our attempts quota
1890
 
 *
1891
 
 * Side effects:
1892
 
 *    Changes 'data'.
1893
 
 *
1894
 
 *-----------------------------------------------------------------------------
1895
 
 */
1896
 
                                                                                
1897
 
Bool
1898
 
ToolsDaemon_CheckReset(ToolsDaemon_Data *data,  // IN/OUT
1899
 
                       uint64 *sleepUsecs)      // IN/OUT
1900
 
{
1901
 
   static int channelTimeoutAttempts = -1;
1902
 
   char *tmp = NULL;
1903
 
                                                                                
1904
 
   ASSERT(data);
1905
 
                                                                                
1906
 
   if (channelTimeoutAttempts < 0) {
1907
 
      Debug("Attempting to retrieve number of channel timeout attempts "
1908
 
            "from vmx\n");
1909
 
      /*
1910
 
       * Currenly, we still use the 'guestinfo' alias. When the main branches
1911
 
       * are synced up and the 'guestvars' code becomes stable, we'll move to
1912
 
       * using the un-prefixed key.
1913
 
       */
1914
 
      if (RpcOut_sendOne(&tmp, NULL,
1915
 
                         "info-get guestinfo.guest_rpc.tclo.timeout") && tmp) {
1916
 
         Debug("Retrieved channel timeout attempts from vmx: %s\n", tmp);
1917
 
         channelTimeoutAttempts = atoi(tmp);
1918
 
      }
1919
 
      free(tmp);
1920
 
      /* Safe-guard attempts against negative and too high-values. */
1921
 
      if (channelTimeoutAttempts <= 0) {
1922
 
         channelTimeoutAttempts = 60;
1923
 
         Debug("Assuming %d channel timeout attempts\n",
1924
 
               channelTimeoutAttempts);
1925
 
      } else if (channelTimeoutAttempts > 180) {
1926
 
         channelTimeoutAttempts = 180;
1927
 
         Debug("Limiting to %d channel timeout attempts\n",
1928
 
               channelTimeoutAttempts);
1929
 
      }
1930
 
      /*
1931
 
       * Double it.  This handles the case where the host is heavily loaded and
1932
 
       * host (real) and guest (virtual) times diverge to the point where the
1933
 
       * guest process timeouts before the VMX can reset the channel.  This
1934
 
       * makes the guest process wait sufficiently long.  Note that since the
1935
 
       * max above is 180 attempts, it is possible to wait 360 * sleepUsecs,
1936
 
       * which by default is 360 seconds.
1937
 
       */
1938
 
      channelTimeoutAttempts *= 2;
1939
 
      Debug("Backdoor resetting will be attemped at most %d times\n",
1940
 
            channelTimeoutAttempts);
1941
 
   }
1942
 
                                                                                
1943
 
   if (data->inError) {
1944
 
      if (++(data->errorCount) > channelTimeoutAttempts) {
1945
 
         Warning("Failed to reset backdoor after %d attempts\n",
1946
 
                 data->errorCount - 1);
1947
 
         return FALSE;
1948
 
      }
1949
 
                                                                                
1950
 
      Debug("Resetting backdoor [%d]\n", data->errorCount);
1951
 
      if (RpcIn_restart(data->in) == FALSE) {
1952
 
         Warning("Backdoor reset failed [%d]\n", data->errorCount);
1953
 
         return FALSE;
1954
 
      }
1955
 
      data->inError = FALSE;
1956
 
                                                                                
1957
 
      *sleepUsecs = (uint64)1000000;
1958
 
   } else {
1959
 
      if ( *sleepUsecs > 0 && data->errorCount > 0) {
1960
 
         Debug("Backdoor was reset successfully\n");
1961
 
         data->errorCount = 0;
1962
 
      }
1963
 
   }
1964
 
   return TRUE;
1965
 
}
1966
 
 
1967
 
 
1968
 
/*
1969
 
 *-----------------------------------------------------------------------------
1970
 
 *
1971
 
 * ToolsDaemon_SetOsPhase --
1972
 
 *
1973
 
 *    Set the guest OS phase in the VMX
1974
 
 *
1975
 
 * Return value:
1976
 
 *    TRUE on success
1977
 
 *    FALSE on failure
1978
 
 *
1979
 
 * Side effects:
1980
 
 *    None
1981
 
 *
1982
 
 *-----------------------------------------------------------------------------
1983
 
 */
1984
 
 
1985
 
Bool
1986
 
ToolsDaemon_SetOsPhase(Bool stateChangeSucceeded, // IN
1987
 
                       unsigned int cmdId)        // IN
1988
 
{
1989
 
   return RpcOut_sendOne(NULL, NULL, "tools.os.statechange.status %d %d",
1990
 
                         stateChangeSucceeded, cmdId);
1991
 
}
1992
 
 
1993
 
 
1994
 
/*
1995
 
 *-----------------------------------------------------------------------------
1996
 
 *
1997
 
 * ToolsDaemon_GetMinResolution --
1998
 
 *
1999
 
 *      Get the minimum resolution (height and width) that we support
2000
 
 *      setting this guest to.
2001
 
 *
2002
 
 *      This was originally added for bug 58681.
2003
 
 *
2004
 
 * Results:
2005
 
 *      None
2006
 
 *
2007
 
 * Side effects:
2008
 
 *      None
2009
 
 *
2010
 
 *-----------------------------------------------------------------------------
2011
 
 */
2012
 
 
2013
 
void
2014
 
ToolsDaemon_GetMinResolution(GuestApp_Dict *dict,    // IN
2015
 
                             unsigned int *width,    // OUT
2016
 
                             unsigned int *height)   // OUT
2017
 
{
2018
 
   ASSERT(width);
2019
 
   ASSERT(height);
2020
 
 
2021
 
   /*
2022
 
    * This code is no longer used for Win9x platforms, and it's assumed that
2023
 
    * all other platforms don't have a minimum.
2024
 
    */
2025
 
   *width = 0;
2026
 
   *height = 0;
2027
 
}
2028
 
 
2029
 
 
2030
 
/*
2031
 
 *-----------------------------------------------------------------------------
2032
 
 *
2033
 
 * ToolsDaemon_GetGuestTempDirectory --
2034
 
 *
2035
 
 *      Return the guest temp directory.
2036
 
 *
2037
 
 * Results:
2038
 
 *      The guest temp directory
2039
 
 *
2040
 
 * Side effects:
2041
 
 *      None
2042
 
 *
2043
 
 *-----------------------------------------------------------------------------
2044
 
 */
2045
 
 
2046
 
const char *
2047
 
ToolsDaemon_GetGuestTempDirectory(void)
2048
 
{
2049
 
   return guestTempDirectory;
2050
 
}
2051
 
 
2052
 
 
2053
 
/*
2054
 
 *-----------------------------------------------------------------------------
2055
 
 *
2056
 
 * ToolsDaemon_InitializeForeignVM --
2057
 
 *
2058
 
 *      This is called when the tools are not running in a VM in VMware.
2059
 
 *      Register appropriate backdoor procedures, and open the foreign tools
2060
 
 *      listener socket.
2061
 
 *
2062
 
 * Results:
2063
 
 *      None
2064
 
 *
2065
 
 * Side effects:
2066
 
 *      None
2067
 
 *
2068
 
 *-----------------------------------------------------------------------------
2069
 
 */
2070
 
 
2071
 
void
2072
 
ToolsDaemon_InitializeForeignVM(ToolsDaemon_Data *toolsDaemonData)   // IN
2073
 
{
2074
 
   Bool success;
2075
 
 
2076
 
   runningInForeignVM = TRUE;
2077
 
 
2078
 
   MessageStub_RegisterTransport();
2079
 
 
2080
 
   success = ForeignTools_Initialize(toolsDaemonData->optionsDict);
2081
 
} // ToolsDaemon_InitializeForeignVM
2082
 
 
2083
 
 
2084
 
/*
2085
 
 *-----------------------------------------------------------------------------
2086
 
 *
2087
 
 * ToolsDaemon_ShutdownForeignVM --
2088
 
 *
2089
 
 *      This is called when the tools are not running in a VM in VMware.
2090
 
 *      Close the foreign tools listener socket.
2091
 
 *
2092
 
 * Results:
2093
 
 *      None
2094
 
 *
2095
 
 * Side effects:
2096
 
 *      None
2097
 
 *
2098
 
 *-----------------------------------------------------------------------------
2099
 
 */
2100
 
 
2101
 
void
2102
 
ToolsDaemon_ShutdownForeignVM(void)
2103
 
{
2104
 
   ForeignTools_Shutdown();
2105
 
} // ToolsDaemon_ShutdownForeignVM
2106
 
 
2107
 
 
2108
 
 
2109
 
 
2110
 
 
2111
 
 
2112
 
#ifdef __cplusplus
2113
 
}
2114
 
#endif