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; }
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); }
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; }