示例#1
0
int
main(int argc,
     char *argv[],
     const char *envp[])
{
   int i;
   int ret = EXIT_FAILURE;
   char **argvCopy;
   GSource *src;

   Unicode_Init(argc, &argv, NULL);

   /*
    * ToolsCore_ParseCommandLine() uses g_option_context_parse(), which modifies
    * argv. We don't want that to happen, so we make a copy of the array and
    * use that as the argument instead.
    */
   argvCopy = g_malloc(argc * sizeof *argvCopy);
   for (i = 0; i < argc; i++) {
      argvCopy[i] = argv[i];
   }

   setlocale(LC_ALL, "");
   VMTools_ConfigLogging(G_LOG_DOMAIN, NULL, FALSE, FALSE);
   VMTools_BindTextDomain(VMW_TEXT_DOMAIN, NULL, NULL);

   if (!ToolsCore_ParseCommandLine(&gState, argc, argvCopy)) {
      g_free(argvCopy);
      goto exit;
   }
   g_free(argvCopy);
   argvCopy = NULL;

   if (gState.pidFile != NULL) {
      /*
       * If argv[0] is not an absolute path, make it so; all other path
       * arguments should have been given as absolute paths if '--background'
       * was used, or things may not work as expected.
       */
      if (!g_path_is_absolute(argv[0])) {
         gchar *abs = g_find_program_in_path(argv[0]);
         if (abs == NULL || strcmp(abs, argv[0]) == 0) {
            char *cwd = File_Cwd(NULL);
            g_free(abs);
            abs = g_strdup_printf("%s%c%s", cwd, DIRSEPC, argv[0]);
            vm_free(cwd);
         }
         argv[0] = abs;
      }

      /*
       * Need to remove --background from the command line or we'll get
       * into an infinite loop. ToolsCore_ParseCommandLine() already
       * validated that "-b" has an argument, so it's safe to assume the
       * data is there.
       */
      for (i = 1; i < argc; i++) {
         size_t count = 0;
         if (strcmp(argv[i], "--background") == 0 ||
             strcmp(argv[i], "-b") == 0) {
            count = 2;
         } else if (g_str_has_prefix(argv[i], "--background=")) {
            count = 1;
         }
         if (count) {
            memmove(argv + i, argv + i + count, (argc - i - count) * sizeof *argv);
            argv[argc - count] = NULL;
            break;
         }
      }

      if (!Hostinfo_Daemonize(argv[0],
                              argv,
                              HOSTINFO_DAEMONIZE_LOCKPID,
                              gState.pidFile, NULL, 0)) {
         goto exit;
      }
      return 0;
   }

   ToolsCore_Setup(&gState);

   src = VMTools_NewSignalSource(SIGHUP);
   VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
                            ToolsCoreSigHUPCb, &gState, NULL);
   g_source_unref(src);

   src = VMTools_NewSignalSource(SIGINT);
   VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
                            ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
   g_source_unref(src);

   src = VMTools_NewSignalSource(SIGQUIT);
   VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
                            ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
   g_source_unref(src);

   src = VMTools_NewSignalSource(SIGTERM);
   VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
                            ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
   g_source_unref(src);

   src = VMTools_NewSignalSource(SIGUSR1);
   VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src, ToolsCoreSigUsrHandler, NULL, NULL);
   g_source_unref(src);

   /* Ignore SIGUSR2 by default. */
   signal(SIGUSR2, SIG_IGN);

   /*
    * Save the original environment so that we can safely spawn other
    * applications (since we may have to modify the original environment
    * to launch vmtoolsd successfully).
    */
   gState.ctx.envp = System_GetNativeEnviron(envp);

   ret = ToolsCore_Run(&gState);

   if (gState.pidFile != NULL) {
      g_unlink(gState.pidFile);
   }
exit:
   return ret;
}
示例#2
0
static gboolean
VmBackupStartCommon(RpcInData *data,
                    gboolean forceQuiesce)
{
   GError *err = NULL;
   ToolsAppCtx *ctx = data->appCtx;
   VmBackupSyncProvider *provider = NULL;

   size_t i;

   /* List of available providers, in order of preference for loading. */
   struct SyncProvider {
      VmBackupSyncProvider *(*ctor)(void);
      const gchar *cfgEntry;
   } providers[] = {
#if defined(_WIN32)
      { VmBackup_NewVssProvider, "enableVSS" },
#endif
      { VmBackup_NewSyncDriverProvider, "enableSyncDriver" },
      { VmBackup_NewNullProvider, NULL },
   };

   if (forceQuiesce) {
      if (gBackupState->quiesceApps || gBackupState->quiesceFS) {
         /*
          * If quiescing is requested on windows platform,
          * only allow VSS provider
          */
#if defined(_WIN32)
         if (VmBackupConfigGetBoolean(ctx->config, "enableVSS", TRUE)) {
            provider = VmBackup_NewVssProvider();
         }
#elif defined(_LINUX) || defined(__linux__)
         /*
          * If quiescing is requested on linux platform,
          * only allow SyncDriver provider
          */
         if (gBackupState->quiesceFS &&
             VmBackupConfigGetBoolean(ctx->config, "enableSyncDriver", TRUE)) {
            provider = VmBackup_NewSyncDriverOnlyProvider();
          }
#endif
      } else {
         /* If no quiescing is requested only allow null provider */
         provider = VmBackup_NewNullProvider();
      }
      if (provider == NULL) {
         g_warning("Requested quiescing cannot be initialized.");
         goto error;
      }
   } else {
      /* Instantiate the sync provider. */
      for (i = 0; i < ARRAYSIZE(providers); i++) {
         struct SyncProvider *sp = &providers[i];

         if (VmBackupConfigGetBoolean(ctx->config, sp->cfgEntry, TRUE)) {
            provider = sp->ctor();
            if (provider != NULL) {
               break;
            }
         }
      }
   }

   ASSERT(provider != NULL);

   /* Instantiate the backup state and start the operation. */
   gBackupState->ctx = data->appCtx;
   gBackupState->pollPeriod = 1000;
   gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
   gBackupState->provider = provider;
   gBackupState->needsPriv = FALSE;
   gBackupState->enableNullDriver = VmBackupConfigGetBoolean(ctx->config,
                                                             "enableNullDriver",
                                                             TRUE);

   g_debug("Using quiesceApps = %d, quiesceFS = %d, allowHWProvider = %d,"
           " execScripts = %d, scriptArg = %s, timeout = %u,"
           " enableNullDriver = %d, forceQuiesce = %d\n",
           gBackupState->quiesceApps, gBackupState->quiesceFS,
           gBackupState->allowHWProvider, gBackupState->execScripts,
           (gBackupState->scriptArg != NULL) ? gBackupState->scriptArg : "",
           gBackupState->timeout, gBackupState->enableNullDriver, forceQuiesce);
   g_debug("Quiescing volumes: %s",
           (gBackupState->volumes) ? gBackupState->volumes : "(null)");

   gBackupState->configDir = GuestApp_GetConfPath();
   if (gBackupState->configDir == NULL) {
      g_warning("Error getting configuration directory.");
      goto error;
   }

   VmBackup_SendEvent(VMBACKUP_EVENT_RESET, VMBACKUP_SUCCESS, "");

   if (!VmBackupStartScripts(VMBACKUP_SCRIPT_FREEZE)) {
      goto error;
   }

   /*
    * VC has a 15 minute timeout for quiesced snapshots. After that timeout,
    * it just discards the operation and sends an error to the caller. But
    * Tools can still keep running, blocking any new quiesced snapshot
    * requests. So we set up our own timer (which is configurable, in case
    * anyone wants to play with it), so that we abort any ongoing operation
    * if we also hit that timeout.
    *
    * First check if the timeout is specified by the RPC command, if not,
    * check the tools.conf file, otherwise use the default.
    *
    * See bug 506106.
    */
   if (gBackupState->timeout == 0) {
      gBackupState->timeout = (guint) g_key_file_get_integer(
                                               gBackupState->ctx->config,
                                               "vmbackup",
                                               "timeout",
                                               &err);
      if (err != NULL) {
         g_clear_error(&err);
         gBackupState->timeout = 15 * 60;
      }
   }

   /* Treat "0" as no timeout. */
   if (gBackupState->timeout != 0) {
      gBackupState->abortTimer =
          g_timeout_source_new_seconds(gBackupState->timeout);
      VMTOOLSAPP_ATTACH_SOURCE(gBackupState->ctx,
                               gBackupState->abortTimer,
                               VmBackupAbortTimer,
                               NULL,
                               NULL);
   }

   VMBACKUP_ENQUEUE_EVENT();
   return RPCIN_SETRETVALS(data, "", TRUE);

error:
   if (gBackupState->keepAlive != NULL) {
      g_source_destroy(gBackupState->keepAlive);
      g_source_unref(gBackupState->keepAlive);
      gBackupState->keepAlive = NULL;
   }
   if (gBackupState->provider) {
      gBackupState->provider->release(gBackupState->provider);
   }
   g_free(gBackupState->scriptArg);
   g_free(gBackupState->volumes);
   g_free(gBackupState);
   gBackupState = NULL;
   return RPCIN_SETRETVALS(data, "Error initializing quiesce operation.",
                           FALSE);
}
gboolean
ToolsDaemonTcloSyncDriverFreeze(RpcInData *data)
{
   static char resultBuffer[DEFAULT_RESULT_MSG_MAX_LENGTH];
   VixError err = VIX_OK;
   char *driveList = NULL;
   char *timeout = NULL;
   int timeoutVal;
   DECLARE_SYNCDRIVER_ERROR(sysError);
   ToolsAppCtx *ctx = data->appCtx;
   GSource *timer;
   
   Debug(">ToolsDaemonTcloSyncDriverFreeze\n");

   /*
    * Parse the arguments
    */
   driveList = ToolsDaemonTcloGetQuotedString(data->args, &data->args);
   timeout = ToolsDaemonTcloGetQuotedString(data->args, &data->args);

   /*
    * Validate the arguments.
    */
   if (NULL == driveList || NULL == timeout) {
      err = VIX_E_INVALID_ARG;
      Debug("ToolsDaemonTcloSyncDriverFreeze: Failed to get string args\n");
      goto abort;
   }

   if (!StrUtil_StrToInt(&timeoutVal, timeout) || timeoutVal < 0) {
      Debug("ToolsDaemonTcloSyncDriverFreeze: Bad args, timeout '%s'\n", timeout);
      err = VIX_E_INVALID_ARG;
      goto abort;
   }

   Debug("SYNCDRIVE: Got request to freeze '%s', timeout %d\n", driveList,
         timeoutVal);

   /* Disallow multiple freeze calls. */
   if (gSyncDriverHandle != SYNCDRIVER_INVALID_HANDLE) {
      err = VIX_E_OBJECT_IS_BUSY;
      goto abort;
   }

   /* Perform the actual freeze. */
   if (!SyncDriver_Freeze(driveList, &gSyncDriverHandle) ||
       SyncDriver_QueryStatus(gSyncDriverHandle, INFINITE) != SYNCDRIVER_IDLE) {
      Debug("ToolsDaemonTcloSyncDriverFreeze: Failed to Freeze drives '%s'\n",
            driveList);
      err = VIX_E_FAIL;
      sysError = SYNCDRIVERERROR;
      if (gSyncDriverHandle != SYNCDRIVER_INVALID_HANDLE) {
         SyncDriver_Thaw(gSyncDriverHandle);
         SyncDriver_CloseHandle(&gSyncDriverHandle);
      }
      goto abort;
   }

   /* Start the timer callback to automatically thaw. */
   if (0 != timeoutVal) {
      Debug("ToolsDaemonTcloSyncDriverFreeze: Starting timer callback %d\n", timeoutVal);
      timer = g_timeout_source_new(timeoutVal * 10);
      VMTOOLSAPP_ATTACH_SOURCE(ctx, timer, ToolsDaemonSyncDriverThawCallback, NULL, NULL);
      g_source_unref(timer);
   }

abort:
   /*
    * These were allocated by ToolsDaemonTcloGetQuotedString.
    */
   free(driveList);
   free(timeout);

   /*
    * All Foundry tools commands return results that start with a
    * foundry error and a guest-OS-specific error.
    */
   Str_Sprintf(resultBuffer, sizeof resultBuffer, "%"FMT64"d %d", err, sysError);
   Debug("<ToolsDaemonTcloSyncDriverFreeze\n");
   return RPCIN_SETRETVALS(data, resultBuffer, TRUE);
}
示例#4
0
Bool
VmBackup_SendEvent(const char *event,
                   const uint32 code,
                   const char *desc)
{
   Bool success;
   char *result = NULL;
   size_t resultLen;
   gchar *msg;

   ASSERT(gBackupState != NULL);

   g_debug("*** %s\n", __FUNCTION__);
   if (gBackupState->keepAlive != NULL) {
      g_source_destroy(gBackupState->keepAlive);
      g_source_unref(gBackupState->keepAlive);
   }

   msg = g_strdup_printf(VMBACKUP_PROTOCOL_EVENT_SET" %s %u %s",
                         event, code, desc);
   g_debug("Sending vmbackup event: %s\n", msg);

#if defined(__linux__)
   if (gBackupState->needsPriv) {
      success = VmBackupPrivSendMsg(msg, &result, &resultLen);
   } else {
      success = RpcChannel_Send(gBackupState->ctx->rpc,
                                msg, strlen(msg) + 1,
                                &result, &resultLen);
      if (!success) {
         const char *privErr = "Guest is not privileged";
         if (resultLen > strlen(privErr) &&
             strncmp(result, privErr, strlen(privErr)) == 0) {
            g_debug("Failed to send event: %s\n", result);
            vm_free(result);

            /*
             * PR1444259:
             * Some hosts enforce privilege elevation for sending this
             * event, especially 5.5. This is Linux specific because
             * version 9.4.x on Linux only triggers host side check for
             * privilege elevation by sending iopl_elevation capability
             * to the host.
             */
            gBackupState->needsPriv = TRUE;

            g_debug("Sending event with priv: %s\n", msg);
            success = VmBackupPrivSendMsg(msg, &result, &resultLen);
         } else {
            gBackupState->needsPriv = FALSE;
         }
      }
   }
#else
   success = RpcChannel_Send(gBackupState->ctx->rpc,
                             msg, strlen(msg) + 1,
                             &result, &resultLen);
#endif

   if (!success) {
      g_warning("Failed to send vmbackup event: %s.\n", result);
   }
   vm_free(result);
   g_free(msg);

   gBackupState->keepAlive = g_timeout_source_new(VMBACKUP_KEEP_ALIVE_PERIOD / 2);
   VMTOOLSAPP_ATTACH_SOURCE(gBackupState->ctx,
                            gBackupState->keepAlive,
                            VmBackupKeepAliveCallback,
                            NULL,
                            NULL);
   return success;
}