/*********************************************************
- * Copyright (C) 2008-2019 VMware, Inc. All rights reserved.
+ * Copyright (C) 2008-2020 VMware, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
}
+/**
+ * Copies the key/value pairs from one config dictionary to another config
+ * dictionary. The key/value pairs are added only if they are not
+ * already present in the destination configuration dictionary.
+ *
+ * @param[in] srcConfig Configuration dictionary from which the
+ * key/value pairs should be added.
+ * @param[in] dstConfig Configuration dictionary to which the
+ * key/value pairs should be added..
+ *
+ * @return Whether any key/value pairs have been added to the config
+ * dictionary.
+ */
+
+gboolean
+VMTools_AddConfig(GKeyFile *srcConfig,
+ GKeyFile *dstConfig)
+{
+ gsize numGroups;
+ gchar **groupNames;
+ gsize i;
+ gboolean configAdded = FALSE;
+
+ g_return_val_if_fail(srcConfig != NULL, configAdded);
+ g_return_val_if_fail(dstConfig != NULL, configAdded);
+
+ groupNames = g_key_file_get_groups(srcConfig, &numGroups);
+
+ g_debug("%s: Found %d groups in config.\n", __FUNCTION__, (int) numGroups);
+
+ for (i = 0; i < numGroups; ++i) {
+ gsize numKeys;
+ gchar **keyNames;
+ gsize j;
+ GError *gErr = NULL;
+ const gchar *group = groupNames[i];
+
+ keyNames = g_key_file_get_keys(srcConfig, group, &numKeys, &gErr);
+ if (gErr != NULL) {
+ g_warning("%s: g_key_file_get_keys(%s) failed: %s\n",
+ __FUNCTION__, group, gErr->message);
+ g_clear_error(&gErr);
+ continue;
+ }
+
+ g_debug("%s: Found %d keys for group: '%s' in config.\n",
+ __FUNCTION__, (int) numKeys, group);
+
+ for (j = 0; j < numKeys; ++j) {
+ const gchar* key = keyNames[j];
+
+ if (!g_key_file_has_key(dstConfig, group, key, NULL)) {
+ gchar *value = g_key_file_get_value(srcConfig, group, key, &gErr);
+
+ if (value == NULL && gErr != NULL) {
+ g_warning("%s: g_key_file_get_value(%s:%s) failed: %s\n",
+ __FUNCTION__, group, key, gErr->message);
+ g_clear_error(&gErr);
+ continue;
+ }
+
+ g_key_file_set_value(dstConfig, group, key, value);
+ g_debug("%s: Added (%s:%s) to the new config\n",
+ __FUNCTION__, group, key);
+ configAdded = TRUE;
+ g_free(value);
+ } else {
+ g_debug("%s: Ignoring (%s:%s)\n", __FUNCTION__, group, key);
+ }
+ }
+
+ g_strfreev(keyNames);
+ }
+
+ g_debug("%s: Added the config. Return val: %d\n", __FUNCTION__, configAdded);
+
+ g_strfreev(groupNames);
+ return configAdded;
+}
+
+
/**
* Saves the given config data to the given path.
*
#if defined(_WIN32)
# include "codeset.h"
# include "guestStoreClient.h"
+# include "globalConfig.h"
# include "windowsu.h"
#else
# include "posix.h"
#define CONFNAME_MAX_CHANNEL_ATTEMPTS "maxChannelAttempts"
+#if defined(_WIN32)
+/*
+ * The state of the global conf module.
+ */
+static gGlobalConfEnabled = FALSE;
+#endif
+
/*
******************************************************************************
}
+#if defined(_WIN32)
+/**
+ * Callback TOOLS_CORE_SIG_GLOBALCONF_UPDATE signal. The signal is
+ * triggered whenever a new global configuration is downloaded.
+ *
+ * @param[in] src The source object.
+ * @param[in] ctx The ToolsAppCtx for passing config.
+ * @param[in] state Service state.
+ */
+
+static void
+ToolsCoreGlobalConfUpdateSignalCb(gpointer src,
+ ToolsAppCtx *ctx,
+ ToolsServiceState *state)
+{
+ g_debug("%s: global config is updated. Reloading the config.", __FUNCTION__);
+
+ ToolsCore_ReloadConfigEx(state, FALSE, TRUE);
+}
+#endif
+
+
/**
* IO freeze signal handler. Disables the conf file check task if I/O is
* frozen, re-enable it otherwise. See bug 529653.
/*
* For now exclude the MAC due to limited testing.
*/
- if (state->mainService && ToolsCoreHangDetector_Start(&state->ctx)) {
- g_info("Successfully started tools hang detector");
+ if (state->mainService) {
+ if (ToolsCoreHangDetector_Start(&state->ctx)) {
+ g_info("%s: Successfully started tools hang detector",
+ __FUNCTION__);
+ }
+#if defined(_WIN32)
+ if (GlobalConfig_Start(&state->ctx)) {
+ g_info("%s: Successfully started global config module.",
+ __FUNCTION__);
+ if (g_signal_lookup(TOOLS_CORE_SIG_GLOBALCONF_UPDATE,
+ G_OBJECT_TYPE(state->ctx.serviceObj)) != 0) {
+ g_signal_connect(state->ctx.serviceObj,
+ TOOLS_CORE_SIG_GLOBALCONF_UPDATE,
+ G_CALLBACK(ToolsCoreGlobalConfUpdateSignalCb),
+ state);
+ g_debug("%s: Registered the handler for the "
+ "global config update signal.", __FUNCTION__);
+ gGlobalConfEnabled = TRUE;
+ } else {
+ g_debug("%s: Failed to register the handler for the "
+ "global config update signal", __FUNCTION__);
+ }
+ }
+#endif
}
+
g_main_loop_run(state->ctx.mainLoop);
#endif
}
*
* @param[in] state Service state.
* @param[in] reset Whether to reset the logging subsystem.
+ * @param[in] force If TRUE, the config file will be loaded even if it
+ * has not been modified since the last check.
*/
void
-ToolsCore_ReloadConfig(ToolsServiceState *state,
- gboolean reset)
+ToolsCore_ReloadConfigEx(ToolsServiceState *state,
+ gboolean reset,
+ gboolean force)
{
gboolean first = state->ctx.config == NULL;
gboolean loaded;
+ if (force) {
+ /*
+ * Set the configMtime to 0 so that the config file from the file system
+ * is reloaded. Else, the config is loaded only if it's been modified
+ * since the last check.
+ */
+ state->configMtime = 0;
+ }
+
loaded = VMTools_LoadConfig(state->configFile,
G_KEY_FILE_NONE,
&state->ctx.config,
&state->configMtime);
+#if defined(_WIN32)
+ if (gGlobalConfEnabled && (loaded || force)) {
+ gboolean globalConfigUpdated = GlobalConfig_Update(state->ctx.config);
+ loaded = loaded || globalConfigUpdated;
+ }
+#endif
if (!first && loaded) {
g_debug("Config file reloaded.\n");
}
+/**
+ * Reloads the config file and re-configure the logging subsystem if the
+ * log file was updated. If the config file is being loaded for the first
+ * time, try to upgrade it to the new version if an old version is
+ * detected.
+ *
+ * @param[in] state Service state.
+ * @param[in] reset Whether to reset the logging subsystem.
+ */
+
+void
+ToolsCore_ReloadConfig(ToolsServiceState *state,
+ gboolean reset)
+{
+ ToolsCore_ReloadConfigEx(state, reset, FALSE);
+}
+
+
#if defined(_WIN32)
/**