[gnome-flashback] monitor-config-store: add way to define config store loading policy
- From: Alberts Muktupāvels <muktupavels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-flashback] monitor-config-store: add way to define config store loading policy
- Date: Mon, 7 Mar 2022 20:15:56 +0000 (UTC)
commit 67cccd0015aca1392f32af126e22bf59fe4d29c7
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date: Mon Mar 7 12:20:23 2022 +0200
monitor-config-store: add way to define config store loading policy
This adds a way to define a way, at the system level, to define a policy
of how monitor configuration files are loaded.
The intended use case is to e.g. either prefer system level monitor
configurations before user levels, or only allow system level
configurations.
Examples:
Prefer system over user level configurations:
<monitors version="2">
<policy>
<stores>
<store>system</store>
<store>user</store>
</stores>
</policy>
<configuration>
...
</configuration>
</monitors>
Only allow system level configurations:
<monitors version="2">
<policy>
<stores>
<store>system</store>
</stores>
</policy>
<configuration>
...
</configuration>
</monitors>
Based on mutter commit:
https://gitlab.gnome.org/GNOME/mutter/-/commit/c611b64c53d16fe252d9f276e5c43b18868740c7
backends/gf-monitor-config-store-private.h | 3 +
backends/gf-monitor-config-store.c | 456 +++++++++++++++++++++++------
2 files changed, 373 insertions(+), 86 deletions(-)
---
diff --git a/backends/gf-monitor-config-store-private.h b/backends/gf-monitor-config-store-private.h
index 573156e..be4bff0 100644
--- a/backends/gf-monitor-config-store-private.h
+++ b/backends/gf-monitor-config-store-private.h
@@ -44,12 +44,15 @@ void gf_monitor_config_store_remove (GfMonitorConf
gboolean gf_monitor_config_store_set_custom (GfMonitorConfigStore *config_store,
const gchar *read_path,
const gchar *write_path,
+ GfMonitorsConfigFlag flags,
GError **error);
gint gf_monitor_config_store_get_config_count (GfMonitorConfigStore *config_store);
GfMonitorManager *gf_monitor_config_store_get_monitor_manager (GfMonitorConfigStore *config_store);
+void gf_monitor_config_store_reset (GfMonitorConfigStore *config_store);
+
G_END_DECLS
#endif
diff --git a/backends/gf-monitor-config-store.c b/backends/gf-monitor-config-store.c
index a509a93..63d2b02 100644
--- a/backends/gf-monitor-config-store.c
+++ b/backends/gf-monitor-config-store.c
@@ -111,6 +111,9 @@ struct _GfMonitorConfigStore
GFile *user_file;
GFile *custom_read_file;
GFile *custom_write_file;
+
+ gboolean has_stores_policy;
+ GList *stores_policy;
};
enum
@@ -152,13 +155,26 @@ typedef enum
STATE_MONITOR_MODE_RATE,
STATE_MONITOR_MODE_FLAG,
STATE_MONITOR_UNDERSCANNING,
- STATE_DISABLED
+ STATE_DISABLED,
+ STATE_POLICY,
+ STATE_STORES,
+ STATE_STORE
} ParserState;
+typedef enum
+{
+ GF_CONFIG_STORE_NONE,
+ GF_CONFIG_STORE_SYSTEM,
+ GF_CONFIG_STORE_USER,
+} GfConfigStore;
+
typedef struct
{
ParserState state;
GfMonitorConfigStore *config_store;
+ GFile *file;
+
+ GHashTable *pending_configs;
ParserState monitor_spec_parent_state;
@@ -172,6 +188,11 @@ typedef struct
GfLogicalMonitorConfig *current_logical_monitor_config;
GList *current_disabled_monitor_specs;
+ gboolean seen_policy;
+ gboolean seen_stores;
+ GfConfigStore pending_store;
+ GList *stores;
+
ParserState unknown_state_root;
int unknown_level;
@@ -197,6 +218,24 @@ static GParamSpec *config_store_properties[LAST_PROP] = { NULL };
G_DEFINE_TYPE (GfMonitorConfigStore, gf_monitor_config_store, G_TYPE_OBJECT)
+static void
+replace_configs (GfMonitorConfigStore *config_store,
+ GHashTable *configs)
+{
+ GHashTableIter iter;
+ GfMonitorsConfigKey *key;
+ GfMonitorsConfig *config;
+
+ g_hash_table_iter_init (&iter, configs);
+ while (g_hash_table_iter_next (&iter,
+ (gpointer *) &key,
+ (gpointer *) &config))
+ {
+ g_hash_table_iter_steal (&iter);
+ g_hash_table_replace (config_store->configs, key, config);
+ }
+}
+
static gboolean
is_system_config (GfMonitorsConfig *config)
{
@@ -282,7 +321,25 @@ handle_start_element (GMarkupParseContext *context,
case STATE_MONITORS:
{
- if (!g_str_equal (element_name, "configuration"))
+ if (g_str_equal (element_name, "configuration"))
+ {
+ parser->state = STATE_CONFIGURATION;
+ parser->current_was_migrated = FALSE;
+ }
+ else if (g_str_equal (element_name, "policy"))
+ {
+ if (parser->seen_policy)
+ {
+ g_set_error (error,
+ G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Multiple policy definitions");
+ return;
+ }
+
+ parser->seen_policy = TRUE;
+ parser->state = STATE_POLICY;
+ }
+ else
{
enter_unknown_element (parser,
element_name,
@@ -291,9 +348,6 @@ handle_start_element (GMarkupParseContext *context,
return;
}
- parser->state = STATE_CONFIGURATION;
- parser->current_was_migrated = FALSE;
-
return;
}
@@ -544,6 +598,62 @@ handle_start_element (GMarkupParseContext *context,
return;
}
+ case STATE_POLICY:
+ {
+ if (!(parser->extra_config_flags & GF_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG))
+ {
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Policy can only be defined in system level configurations");
+ return;
+ }
+
+ if (g_str_equal (element_name, "stores"))
+ {
+ if (parser->seen_stores)
+ {
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Multiple stores elements under policy");
+ return;
+ }
+
+ parser->seen_stores = TRUE;
+ parser->state = STATE_STORES;
+ }
+ else
+ {
+ enter_unknown_element (parser,
+ element_name,
+ "policy",
+ STATE_POLICY);
+ }
+
+ return;
+ }
+
+ case STATE_STORES:
+ {
+ if (g_str_equal (element_name, "store"))
+ {
+ parser->state = STATE_STORE;
+ }
+ else
+ {
+ enter_unknown_element (parser,
+ element_name,
+ "stores",
+ STATE_STORES);
+ }
+
+ return;
+ }
+
+ case STATE_STORE:
+ {
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Invalid store sub element '%s'", element_name);
+ return;
+ }
+
default:
break;
}
@@ -653,6 +763,9 @@ finish_monitor_spec (ConfigParser *parser)
case STATE_MONITOR_MODE_RATE:
case STATE_MONITOR_MODE_FLAG:
case STATE_MONITOR_UNDERSCANNING:
+ case STATE_POLICY:
+ case STATE_STORES:
+ case STATE_STORE:
default:
g_assert_not_reached ();
break;
@@ -863,13 +976,65 @@ handle_end_element (GMarkupParseContext *context,
return;
}
- g_hash_table_replace (parser->config_store->configs,
+ g_hash_table_replace (parser->pending_configs,
config->key, config);
parser->state = STATE_MONITORS;
return;
}
+ case STATE_STORE:
+ g_assert (g_str_equal (element_name, "store"));
+
+ if (parser->pending_store == GF_CONFIG_STORE_NONE)
+ {
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Got an empty store");
+ return;
+ }
+
+ if (g_list_find (parser->stores,
+ GINT_TO_POINTER (parser->pending_store)))
+ {
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Multiple identical stores in policy");
+ return;
+ }
+
+ parser->stores =
+ g_list_append (parser->stores,
+ GINT_TO_POINTER (parser->pending_store));
+ parser->pending_store = GF_CONFIG_STORE_NONE;
+
+ parser->state = STATE_STORES;
+ return;
+
+ case STATE_STORES:
+ g_assert (g_str_equal (element_name, "stores"));
+
+ if (parser->config_store->has_stores_policy)
+ {
+ g_warning ("Ignoring stores policy from '%s', "
+ "it has already been configured",
+ g_file_peek_path (parser->file));
+ g_clear_pointer (&parser->stores, g_list_free);
+ }
+ else
+ {
+ parser->config_store->has_stores_policy = TRUE;
+ parser->config_store->stores_policy = parser->stores;
+ parser->stores = NULL;
+ }
+
+ parser->state = STATE_POLICY;
+ return;
+
+ case STATE_POLICY:
+ g_assert (g_str_equal (element_name, "policy"));
+
+ parser->state = STATE_MONITORS;
+ return;
+
case STATE_UNKNOWN:
{
parser->unknown_level--;
@@ -1015,6 +1180,8 @@ handle_text (GMarkupParseContext *context,
case STATE_MONITOR_MODE:
case STATE_TRANSFORM:
case STATE_DISABLED:
+ case STATE_POLICY:
+ case STATE_STORES:
{
if (!is_all_whitespace (text, text_len))
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
@@ -1165,6 +1332,36 @@ handle_text (GMarkupParseContext *context,
return;
}
+ case STATE_STORE:
+ {
+ GfConfigStore store;
+
+ if (parser->pending_store != GF_CONFIG_STORE_NONE)
+ {
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Multiple store strings");
+ return;
+ }
+
+ if (text_equals (text, text_len, "system"))
+ {
+ store = GF_CONFIG_STORE_SYSTEM;
+ }
+ else if (text_equals (text, text_len, "user"))
+ {
+ store = GF_CONFIG_STORE_USER;
+ }
+ else
+ {
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Invalid store %.*s", (int) text_len, text);
+ return;
+ }
+
+ parser->pending_store = store;
+ return;
+ }
+
default:
break;
}
@@ -1181,6 +1378,7 @@ static gboolean
read_config_file (GfMonitorConfigStore *config_store,
GFile *file,
GfMonitorsConfigFlag extra_config_flags,
+ GHashTable **out_configs,
GError **error)
{
gchar *buffer;
@@ -1196,9 +1394,15 @@ read_config_file (GfMonitorConfigStore *config_store,
parser = (ConfigParser) {
.state = STATE_INITIAL,
+ .file = file,
.config_store = config_store,
+ .pending_configs = g_hash_table_new_full (gf_monitors_config_key_hash,
+ gf_monitors_config_key_equal,
+ NULL,
+ g_object_unref),
.extra_config_flags = extra_config_flags,
- .unknown_state_root = -1
+ .unknown_state_root = -1,
+ .pending_store = GF_CONFIG_STORE_NONE
};
parse_context = g_markup_parse_context_new (&config_parser,
@@ -1218,12 +1422,18 @@ read_config_file (GfMonitorConfigStore *config_store,
g_clear_pointer (&parser.current_logical_monitor_config,
gf_logical_monitor_config_free);
+ g_list_free (parser.stores);
+ g_hash_table_unref (parser.pending_configs);
+
g_markup_parse_context_free (parse_context);
g_free (buffer);
return FALSE;
}
+ *out_configs = parser.pending_configs;
+ parser.pending_configs = NULL;
+
g_markup_parse_context_free (parse_context);
g_free (buffer);
@@ -1555,85 +1765,12 @@ static void
gf_monitor_config_store_constructed (GObject *object)
{
GfMonitorConfigStore *config_store;
- const char * const *system_dirs;
- char *user_file_path;
- GError *error;
G_OBJECT_CLASS (gf_monitor_config_store_parent_class)->constructed (object);
config_store = GF_MONITOR_CONFIG_STORE (object);
- error = NULL;
-
- for (system_dirs = g_get_system_config_dirs ();
- system_dirs && *system_dirs;
- system_dirs++)
- {
- char *system_file_path;
-
- system_file_path = g_build_filename (*system_dirs, "monitors.xml", NULL);
-
- if (g_file_test (system_file_path, G_FILE_TEST_EXISTS))
- {
- GFile *system_file;
- system_file = g_file_new_for_path (system_file_path);
-
- if (!read_config_file (config_store,
- system_file,
- GF_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG,
- &error))
- {
- if (g_error_matches (error,
- GF_MONITOR_CONFIG_STORE_ERROR,
- GF_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION))
- g_warning ("System monitor configuration file (%s) is "
- "incompatible; ask your administrator to migrate "
- "the system monitor configuration.",
- system_file_path);
- else
- g_warning ("Failed to read monitors config file '%s': %s",
- system_file_path, error->message);
-
- g_clear_error (&error);
- }
-
- g_object_unref (system_file);
- }
-
- g_free (system_file_path);
- }
-
- user_file_path = g_build_filename (g_get_user_config_dir (), "monitors.xml", NULL);
- config_store->user_file = g_file_new_for_path (user_file_path);
-
- if (g_file_test (user_file_path, G_FILE_TEST_EXISTS))
- {
- if (!read_config_file (config_store,
- config_store->user_file,
- GF_MONITORS_CONFIG_FLAG_NONE,
- &error))
- {
- if (error->domain == GF_MONITOR_CONFIG_STORE_ERROR &&
- error->code == GF_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION)
- {
- g_clear_error (&error);
- if (!gf_migrate_old_user_monitors_config (config_store, &error))
- {
- g_warning ("Failed to migrate old monitors config file: %s",
- error->message);
- g_error_free (error);
- }
- }
- else
- {
- g_warning ("Failed to read monitors config file '%s': %s",
- user_file_path, error->message);
- g_error_free (error);
- }
- }
- }
-
- g_free (user_file_path);
+ gf_monitor_config_store_reset (config_store);
}
static void
@@ -1658,6 +1795,7 @@ gf_monitor_config_store_dispose (GObject *object)
g_clear_object (&config_store->user_file);
g_clear_object (&config_store->custom_read_file);
g_clear_object (&config_store->custom_write_file);
+ g_clear_pointer (&config_store->stores_policy, g_list_free);
G_OBJECT_CLASS (gf_monitor_config_store_parent_class)->dispose (object);
}
@@ -1778,20 +1916,34 @@ gboolean
gf_monitor_config_store_set_custom (GfMonitorConfigStore *config_store,
const gchar *read_path,
const gchar *write_path,
+ GfMonitorsConfigFlag config_flags,
GError **error)
{
+ GHashTable *new_configs;
+
+ new_configs = NULL;
+
g_clear_object (&config_store->custom_read_file);
g_clear_object (&config_store->custom_write_file);
- g_hash_table_remove_all (config_store->configs);
config_store->custom_read_file = g_file_new_for_path (read_path);
if (write_path)
config_store->custom_write_file = g_file_new_for_path (write_path);
- return read_config_file (config_store,
- config_store->custom_read_file,
- GF_MONITORS_CONFIG_FLAG_NONE,
- error);
+ g_clear_pointer (&config_store->stores_policy, g_list_free);
+ config_store->has_stores_policy = FALSE;
+
+ if (!read_config_file (config_store,
+ config_store->custom_read_file,
+ config_flags,
+ &new_configs,
+ error))
+ return FALSE;
+
+ g_clear_pointer (&config_store->configs, g_hash_table_unref);
+ config_store->configs = new_configs;
+
+ return TRUE;
}
gint
@@ -1805,3 +1957,135 @@ gf_monitor_config_store_get_monitor_manager (GfMonitorConfigStore *config_store)
{
return config_store->monitor_manager;
}
+
+void
+gf_monitor_config_store_reset (GfMonitorConfigStore *config_store)
+{
+ GHashTable *system_configs;
+ GHashTable *user_configs;
+ const char * const *system_dirs;
+ char *user_file_path;
+ GError *error;
+
+ system_configs = NULL;
+ user_configs = NULL;
+ error = NULL;
+
+ g_clear_object (&config_store->user_file);
+ g_clear_object (&config_store->custom_read_file);
+ g_clear_object (&config_store->custom_write_file);
+ g_hash_table_remove_all (config_store->configs);
+
+ for (system_dirs = g_get_system_config_dirs ();
+ system_dirs && *system_dirs;
+ system_dirs++)
+ {
+ char *system_file_path;
+
+ system_file_path = g_build_filename (*system_dirs, "monitors.xml", NULL);
+
+ if (g_file_test (system_file_path, G_FILE_TEST_EXISTS))
+ {
+ GFile *system_file;
+
+ system_file = g_file_new_for_path (system_file_path);
+
+ if (!read_config_file (config_store,
+ system_file,
+ GF_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG,
+ &system_configs,
+ &error))
+ {
+ if (g_error_matches (error,
+ GF_MONITOR_CONFIG_STORE_ERROR,
+ GF_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION))
+ g_warning ("System monitor configuration file (%s) is "
+ "incompatible; ask your administrator to migrate "
+ "the system monitor configuration.",
+ system_file_path);
+ else
+ g_warning ("Failed to read monitors config file '%s': %s",
+ system_file_path, error->message);
+
+ g_clear_error (&error);
+ }
+
+ g_object_unref (system_file);
+ }
+
+ g_free (system_file_path);
+ }
+
+ user_file_path = g_build_filename (g_get_user_config_dir (), "monitors.xml", NULL);
+ config_store->user_file = g_file_new_for_path (user_file_path);
+
+ if (g_file_test (user_file_path, G_FILE_TEST_EXISTS))
+ {
+ if (!read_config_file (config_store,
+ config_store->user_file,
+ GF_MONITORS_CONFIG_FLAG_NONE,
+ &user_configs,
+ &error))
+ {
+ if (error->domain == GF_MONITOR_CONFIG_STORE_ERROR &&
+ error->code == GF_MONITOR_CONFIG_STORE_ERROR_NEEDS_MIGRATION)
+ {
+ g_clear_error (&error);
+ if (!gf_migrate_old_user_monitors_config (config_store, &error))
+ {
+ g_warning ("Failed to migrate old monitors config file: %s",
+ error->message);
+ g_error_free (error);
+ }
+ }
+ else
+ {
+ g_warning ("Failed to read monitors config file '%s': %s",
+ user_file_path, error->message);
+ g_error_free (error);
+ }
+ }
+ }
+
+ if (config_store->has_stores_policy)
+ {
+ GList *l;
+
+ for (l = g_list_last (config_store->stores_policy); l; l = l->prev)
+ {
+ GfConfigStore store;
+
+ store = GPOINTER_TO_INT (l->data);
+
+ switch (store)
+ {
+ case GF_CONFIG_STORE_SYSTEM:
+ if (system_configs)
+ replace_configs (config_store, system_configs);
+ break;
+
+ case GF_CONFIG_STORE_USER:
+ if (user_configs)
+ replace_configs (config_store, user_configs);
+ break;
+
+ case GF_CONFIG_STORE_NONE:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (system_configs)
+ replace_configs (config_store, system_configs);
+
+ if (user_configs)
+ replace_configs (config_store, user_configs);
+ }
+
+ g_clear_pointer (&system_configs, g_hash_table_unref);
+ g_clear_pointer (&user_configs, g_hash_table_unref);
+ g_free (user_file_path);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]