diff options
author | Christian Persch <chpe@src.gnome.org> | 2022-08-26 22:10:31 +0200 |
---|---|---|
committer | Christian Persch <chpe@src.gnome.org> | 2022-08-26 22:10:31 +0200 |
commit | 24371c711ec61943a89eabc36c1450fe7e999930 (patch) | |
tree | 6942e15e6ca14bd5016d0aff6a8eec9f19b0ae9c /src | |
parent | 267e79ee128a956da7769882e5c7d29967cebac6 (diff) | |
download | gnome-terminal-24371c711ec61943a89eabc36c1450fe7e999930.tar.gz |
settings: Consolidate settings related code into one source file
Diffstat (limited to 'src')
-rw-r--r-- | src/meson.build | 2 | ||||
-rw-r--r-- | src/terminal-app.cc | 1 | ||||
-rw-r--r-- | src/terminal-client-utils.cc | 96 | ||||
-rw-r--r-- | src/terminal-client-utils.hh | 9 | ||||
-rw-r--r-- | src/terminal-settings-list.cc | 1 | ||||
-rw-r--r-- | src/terminal-settings-utils.cc | 479 | ||||
-rw-r--r-- | src/terminal-settings-utils.hh | 49 | ||||
-rw-r--r-- | src/terminal-util.cc | 377 | ||||
-rw-r--r-- | src/terminal-util.hh | 2 |
9 files changed, 522 insertions, 494 deletions
diff --git a/src/meson.build b/src/meson.build index 72ead5ab..6676fbb2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -346,7 +346,7 @@ prefs_main = executable( # Legacy client -client_sources = client_util_sources + debug_sources + dbus_sources + i18n_sources + profiles_sources + types_sources + files( +client_sources = client_util_sources + debug_sources + dbus_sources + i18n_sources + profiles_sources + settings_utils_sources + types_sources + files( 'terminal-options.cc', 'terminal-options.hh', 'terminal.cc', diff --git a/src/terminal-app.cc b/src/terminal-app.cc index 4dab8d36..59a4db15 100644 --- a/src/terminal-app.cc +++ b/src/terminal-app.cc @@ -36,6 +36,7 @@ #include "terminal-profiles-list.hh" #include "terminal-util.hh" #include "terminal-schemas.hh" +#include "terminal-settings-utils.hh" #include "terminal-defines.hh" #include "terminal-libgsystem.hh" diff --git a/src/terminal-client-utils.cc b/src/terminal-client-utils.cc index d20f984a..8604a22d 100644 --- a/src/terminal-client-utils.cc +++ b/src/terminal-client-utils.cc @@ -430,99 +430,3 @@ out: #endif return nullptr; } - -#ifdef ENABLE_DEBUG - -static gboolean -settings_change_event_cb(GSettings* settings, - void* keys, - int n_keys, - void* data) -{ - gs_free char* schema_id = nullptr; - gs_free char* path = nullptr; - g_object_get(settings, - "schema-id", &schema_id, - "path", &path, - nullptr); - - auto const qkeys = reinterpret_cast<GQuark*>(keys); - for (auto i = 0; i < n_keys; ++i) { - auto key = g_quark_to_string(qkeys[i]); - _terminal_debug_print(TERMINAL_DEBUG_BRIDGE, - "Bridge backend ::change-event schema %s path %s key %s\n", - schema_id, path, key); - } - - return false; // propagate -} - -static gboolean -settings_writable_change_event_cb(GSettings* settings, - char const* key, - void* data) -{ - gs_free char* schema_id = nullptr; - gs_free char* path = nullptr; - g_object_get(settings, - "schema-id", &schema_id, - "path", &path, - nullptr); - - _terminal_debug_print(TERMINAL_DEBUG_BRIDGE, - "Bridge backend ::writeable-change-event schema %s path %s key %s\n", - schema_id, path, key); - - return false; // propagate -} - -#endif /* ENABLE_DEBUG */ - -GSettings* -terminal_g_settings_new_with_path (GSettingsBackend* backend, - GSettingsSchemaSource* source, - char const* schema_id, - char const* path) -{ - gs_unref_settings_schema GSettingsSchema* schema = - g_settings_schema_source_lookup(source, - schema_id, - TRUE /* recursive */); - g_assert_nonnull(schema); - - auto const settings = g_settings_new_full(schema, - backend, - path); - -#ifdef ENABLE_DEBUG - _TERMINAL_DEBUG_IF(TERMINAL_DEBUG_BRIDGE) { - - _terminal_debug_print(TERMINAL_DEBUG_BRIDGE, - "Creating GSettings for schema %s at %s with backend %s\n", - schema_id, path, - backend ? G_OBJECT_TYPE_NAME(backend) : "(default)"); - - if (backend != nullptr && - g_str_equal(G_OBJECT_TYPE_NAME(backend), "TerminalSettingsBridgeBackend")) { - g_signal_connect(settings, - "change-event", - G_CALLBACK(settings_change_event_cb), - nullptr); - g_signal_connect(settings, - "writable-change-event", - G_CALLBACK(settings_writable_change_event_cb), - nullptr); - } - } -#endif /* ENABLE_DEBUG */ - - return settings; -} - -GSettings* -terminal_g_settings_new(GSettingsBackend* backend, - GSettingsSchemaSource* source, - char const* schema_id) -{ - return terminal_g_settings_new_with_path(backend, source, schema_id, nullptr); -} diff --git a/src/terminal-client-utils.hh b/src/terminal-client-utils.hh index ed556de5..33e5c909 100644 --- a/src/terminal-client-utils.hh +++ b/src/terminal-client-utils.hh @@ -65,15 +65,6 @@ char const* const* terminal_client_get_environment_prefix_filters (void); char** terminal_client_filter_environment (char** envv) G_GNUC_MALLOC; -GSettings* terminal_g_settings_new (GSettingsBackend* backend, - GSettingsSchemaSource* source, - char const* schema_id); - -GSettings* terminal_g_settings_new_with_path (GSettingsBackend* backend, - GSettingsSchemaSource* source, - char const* schema_id, - char const* path); - G_END_DECLS #endif /* TERMINAL_UTIL_UTILS_H */ diff --git a/src/terminal-settings-list.cc b/src/terminal-settings-list.cc index 03f85999..12d74a4a 100644 --- a/src/terminal-settings-list.cc +++ b/src/terminal-settings-list.cc @@ -27,6 +27,7 @@ #include <gio/gsettingsbackend.h> #include "terminal-type-builtins.hh" +#include "terminal-settings-utils.hh" #include "terminal-schemas.hh" #include "terminal-debug.hh" #include "terminal-dconf.hh" diff --git a/src/terminal-settings-utils.cc b/src/terminal-settings-utils.cc index 9110d4b5..0b52ef8a 100644 --- a/src/terminal-settings-utils.cc +++ b/src/terminal-settings-utils.cc @@ -19,8 +19,483 @@ #define G_SETTINGS_ENABLE_BACKEND #include "terminal-settings-utils.hh" +#include "terminal-client-utils.hh" +#include "terminal-debug.hh" +#include "terminal-libgsystem.hh" -#include <gio/gio.h> +#ifdef ENABLE_DEBUG + +static gboolean +settings_change_event_cb(GSettings* settings, + void* keys, + int n_keys, + void* data) +{ + gs_free char* schema_id = nullptr; + gs_free char* path = nullptr; + g_object_get(settings, + "schema-id", &schema_id, + "path", &path, + nullptr); + + auto const qkeys = reinterpret_cast<GQuark*>(keys); + for (auto i = 0; i < n_keys; ++i) { + auto key = g_quark_to_string(qkeys[i]); + _terminal_debug_print(TERMINAL_DEBUG_BRIDGE, + "Bridge backend ::change-event schema %s path %s key %s\n", + schema_id, path, key); + } + + return false; // propagate +} + +static gboolean +settings_writable_change_event_cb(GSettings* settings, + char const* key, + void* data) +{ + gs_free char* schema_id = nullptr; + gs_free char* path = nullptr; + g_object_get(settings, + "schema-id", &schema_id, + "path", &path, + nullptr); + + _terminal_debug_print(TERMINAL_DEBUG_BRIDGE, + "Bridge backend ::writeable-change-event schema %s path %s key %s\n", + schema_id, path, key); + + return false; // propagate +} + +#endif /* ENABLE_DEBUG */ + +GSettings* +terminal_g_settings_new_with_path (GSettingsBackend* backend, + GSettingsSchemaSource* source, + char const* schema_id, + char const* path) +{ + gs_unref_settings_schema GSettingsSchema* schema = + g_settings_schema_source_lookup(source, + schema_id, + TRUE /* recursive */); + g_assert_nonnull(schema); + + auto const settings = g_settings_new_full(schema, + backend, + path); + +#ifdef ENABLE_DEBUG + _TERMINAL_DEBUG_IF(TERMINAL_DEBUG_BRIDGE) { + + _terminal_debug_print(TERMINAL_DEBUG_BRIDGE, + "Creating GSettings for schema %s at %s with backend %s\n", + schema_id, path, + backend ? G_OBJECT_TYPE_NAME(backend) : "(default)"); + + if (backend != nullptr && + g_str_equal(G_OBJECT_TYPE_NAME(backend), "TerminalSettingsBridgeBackend")) { + g_signal_connect(settings, + "change-event", + G_CALLBACK(settings_change_event_cb), + nullptr); + g_signal_connect(settings, + "writable-change-event", + G_CALLBACK(settings_writable_change_event_cb), + nullptr); + } + } +#endif /* ENABLE_DEBUG */ + + return settings; +} + +GSettings* +terminal_g_settings_new(GSettingsBackend* backend, + GSettingsSchemaSource* source, + char const* schema_id) +{ + return terminal_g_settings_new_with_path(backend, source, schema_id, nullptr); +} + +#if defined(TERMINAL_SERVER) || defined(TERMINAL_PREFERENCES) + +#define TERMINAL_SCHEMA_VERIFIER_ERROR (g_quark_from_static_string("TerminalSchemaVerifier")) + +typedef enum { + TERMINAL_SCHEMA_VERIFIER_SCHEMA_MISSING, + TERMINAL_SCHEMA_VERIFIER_SCHEMA_PATH, + TERMINAL_SCHEMA_VERIFIER_KEY_MISSING, + TERMINAL_SCHEMA_VERIFIER_KEY_TYPE, + TERMINAL_SCHEMA_VERIFIER_KEY_DEFAULT, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_UNKNOWN, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_MISMATCH, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_ENUM_VALUE, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_INTERVAL, + TERMINAL_SCHEMA_VERIFIER_CHILD_MISSING, +} TerminalSchemaVerifierError; + +static gboolean +strv_contains(char const* const* strv, + char const* str) +{ + if (strv == nullptr) + return FALSE; + + for (size_t i = 0; strv[i]; i++) { + if (g_str_equal (strv[i], str)) + return TRUE; + } + + return FALSE; +} + +static gboolean +schema_key_range_compatible(GSettingsSchema* source_schema, + GSettingsSchemaKey* source_key, + char const* key, + GSettingsSchemaKey* reference_key, + GError** error) +{ + gs_unref_variant GVariant* source_range = + g_settings_schema_key_get_range(source_key); + gs_unref_variant GVariant* reference_range = + g_settings_schema_key_get_range(reference_key); + + char const* source_type = nullptr; + gs_unref_variant GVariant* source_data = nullptr; + g_variant_get(source_range, "(&sv)", &source_type, &source_data); + + char const* reference_type = nullptr; + gs_unref_variant GVariant* reference_data = nullptr; + g_variant_get(reference_range, "(&sv)", &reference_type, &reference_data); + + if (!g_str_equal(source_type, reference_type)) { + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE, + "Schema \"%s\" key \"%s\" has range type \"%s\" but reference range type is \"%s\"", + g_settings_schema_get_id(source_schema), + key, source_type, reference_type); + return FALSE; + } + + if (g_str_equal(reference_type, "type")) + ; /* no constraints; this is fine */ + else if (g_str_equal(reference_type, "enum")) { + size_t source_values_len = 0; + gs_free char const** source_values = g_variant_get_strv(source_data, &source_values_len); + + size_t reference_values_len = 0; + gs_free char const** reference_values = g_variant_get_strv(reference_data, &reference_values_len); + + /* Check that every enum value in source is valid according to the reference */ + for (size_t i = 0; i < source_values_len; ++i) { + if (!strv_contains(reference_values, source_values[i])) { + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_ENUM_VALUE, + "Schema \"%s\" key \"%s\" has enum value \"%s\" not in reference schema", + g_settings_schema_get_id(source_schema), + key, source_values[i]); + return FALSE; + } + } + } else if (g_str_equal(reference_type, "flags")) { + /* Our schemas don't use flags. If that changes, need to implement this! */ + g_assert_not_reached(); + } else if (g_str_equal(reference_type, "range")) { + if (!g_variant_is_of_type(source_data, + g_variant_get_type(reference_data))) { + char const* source_type_str = g_variant_get_type_string(source_data); + char const* reference_type_str = g_variant_get_type_string(reference_data); + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_MISMATCH, + "Schema \"%s\" key \"%s\" has range type \"%s\" but reference range type is \"%s\"", + g_settings_schema_get_id(source_schema), + key, source_type_str, reference_type_str); + return FALSE; + } + + gs_unref_variant GVariant* reference_min = nullptr; + gs_unref_variant GVariant* reference_max = nullptr; + g_variant_get(reference_data, "(**)", &reference_min, &reference_max); + + gs_unref_variant GVariant* source_min = nullptr; + gs_unref_variant GVariant* source_max = nullptr; + g_variant_get(source_data, "(**)", &source_min, &source_max); + + /* The source interval must be contained within the reference interval */ + if (g_variant_compare(source_min, reference_min) < 0 || + g_variant_compare(source_max, reference_max) > 0) { + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_INTERVAL, + "Schema \"%s\" key \"%s\" has range interval not contained in reference range interval", + g_settings_schema_get_id(source_schema), key); + return FALSE; + } + } else { + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_UNKNOWN, + "Schema \"%s\" key \"%s\" has unknown range type \"%s\"", + g_settings_schema_get_id(source_schema), + key, reference_type); + return FALSE; + } + + return TRUE; +} + +static gboolean +schema_verify_key(GSettingsSchema* source_schema, + char const* key, + GSettingsSchema* reference_schema, + GError** error) +{ + if (!g_settings_schema_has_key(source_schema, key)) { + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_KEY_MISSING, + "Schema \"%s\" has missing key \"%s\"", + g_settings_schema_get_id(source_schema), key); + return FALSE; + } + + gs_unref_settings_schema_key GSettingsSchemaKey* source_key = + g_settings_schema_get_key(source_schema, key); + g_assert_nonnull(source_key); + + gs_unref_settings_schema_key GSettingsSchemaKey* reference_key = + g_settings_schema_get_key(reference_schema, key); + g_assert_nonnull(reference_key); + + GVariantType const* source_type = g_settings_schema_key_get_value_type(source_key); + GVariantType const* reference_type = g_settings_schema_key_get_value_type(reference_key); + if (!g_variant_type_equal(source_type, reference_type)) { + gs_free char* source_type_str = g_variant_type_dup_string(source_type); + gs_free char* reference_type_str = g_variant_type_dup_string(reference_type); + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_KEY_TYPE, + "Schema \"%s\" has type \"%s\" but reference type is \"%s\"", + g_settings_schema_get_id(source_schema), + source_type_str, reference_type_str); + return FALSE; + } + + gs_unref_variant GVariant* source_default = g_settings_schema_key_get_default_value(source_key); + if (!g_settings_schema_key_range_check(reference_key, source_default)) { + gs_free char* source_value_str = g_variant_print(source_default, TRUE); + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_KEY_DEFAULT, + "Schema \"%s\" default value \"%s\" does not conform to reference schema", + g_settings_schema_get_id(source_schema), source_value_str); + return FALSE; + } + + if (!schema_key_range_compatible(source_schema, + source_key, + key, + reference_key, + error)) + return FALSE; + + return TRUE; +} + +static gboolean +schema_verify_child(GSettingsSchema* source_schema, + char const* child_name, + GSettingsSchema* reference_schema, + GError** error) +{ + /* Should verify the child's schema ID is as expected and exists in + * the source, but there appears to be no API to get the schema ID of + * the child. + * + * We work around this missing verification by never calling + * g_settings_get_child() and instead always constructing the child + * GSettings directly; and the existence and correctness of that + * schema is verified by the per-schema checks. + */ + + return TRUE; +} + +static gboolean +schema_verify(GSettingsSchema* source_schema, + GSettingsSchema* reference_schema, + GError** error) +{ + /* Verify path */ + char const* source_path = g_settings_schema_get_path(source_schema); + char const* reference_path = g_settings_schema_get_path(reference_schema); + if (g_strcmp0(source_path, reference_path) != 0) { + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_SCHEMA_PATH, + "Schema \"%s\" has path \"%s\" but reference path is \"%s\"", + g_settings_schema_get_id(source_schema), + source_path ? source_path : "(null)", + reference_path ? reference_path : "(null)"); + return FALSE; + } + + /* Verify keys */ + gs_strfreev char** keys = g_settings_schema_list_keys(reference_schema); + if (keys) { + for (int i = 0; keys[i]; ++i) { + if (!schema_verify_key(source_schema, + keys[i], + reference_schema, + error)) + return FALSE; + } + } + + /* Verify child schemas */ + gs_strfreev char** source_children = g_settings_schema_list_children(source_schema); + gs_strfreev char** reference_children = g_settings_schema_list_children(reference_schema); + if (reference_children) { + for (size_t i = 0; reference_children[i]; ++i) { + if (!strv_contains((char const* const*)source_children, reference_children[i])) { + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_CHILD_MISSING, + "Schema \"%s\" has missing child \"%s\"", + g_settings_schema_get_id(source_schema), + reference_children[i]); + return FALSE; + } + + if (!schema_verify_child(source_schema, + reference_children[i], + reference_schema, + error)) + return FALSE; + } + } + + return TRUE; +} + +static gboolean +schemas_source_verify_schema_by_name(GSettingsSchemaSource* source, + char const* schema_name, + GSettingsSchemaSource* reference_source, + GError** error) +{ + gs_unref_settings_schema GSettingsSchema* source_schema = + g_settings_schema_source_lookup(source, schema_name, TRUE /* recursive */); + + if (!source_schema) { + g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, + TERMINAL_SCHEMA_VERIFIER_SCHEMA_MISSING, + "Schema \"%s\" is missing", schema_name); + return FALSE; + } + + gs_unref_settings_schema GSettingsSchema* reference_schema = + g_settings_schema_source_lookup(reference_source, + schema_name, + FALSE /* recursive */); + g_assert_nonnull(reference_schema); + + return schema_verify(source_schema, + reference_schema, + error); +} + +static gboolean +schemas_source_verify_schemas(GSettingsSchemaSource* source, + char const* const* schemas, + GSettingsSchemaSource* reference_source, + GError** error) +{ + if (!schemas) + return TRUE; + + for (int i = 0; schemas[i]; ++i) { + if (!schemas_source_verify_schema_by_name(source, + schemas[i], + reference_source, + error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +schemas_source_verify(GSettingsSchemaSource* source, + GSettingsSchemaSource* reference_source, + GError** error) +{ + gs_strfreev char** reloc_schemas = nullptr; + gs_strfreev char** nonreloc_schemas = nullptr; + + g_settings_schema_source_list_schemas(reference_source, + FALSE /* recursive */, + &reloc_schemas, + &nonreloc_schemas); + + if (!schemas_source_verify_schemas(source, + (char const* const*)reloc_schemas, + reference_source, + error)) + return FALSE; + + if (!schemas_source_verify_schemas(source, + (char const* const*)nonreloc_schemas, + reference_source, + error)) + return FALSE; + + return TRUE; +} + +GSettingsSchemaSource* +terminal_g_settings_schema_source_get_default(void) +{ + GSettingsSchemaSource* default_source = g_settings_schema_source_get_default(); + + gs_free auto schema_dir = + terminal_client_get_directory_uninstalled( +#if defined(TERMINAL_SERVER) + TERM_LIBEXECDIR, +#elif defined(TERMINAL_PREFERENCES) + TERM_PKGLIBDIR, +#else +#error Need to define installed location +#endif + TERM_PKGLIBDIR, + "gschemas.compiled", + GFileTest(0)); + + gs_free_error GError* error = nullptr; + GSettingsSchemaSource* reference_source = + g_settings_schema_source_new_from_directory(schema_dir, + nullptr /* parent source */, + FALSE /* trusted */, + &error); + if (!reference_source) { + /* Can only use the installed schemas, or abort here. */ + g_printerr("Failed to load reference schemas: %s\n" + "Using unverified installed schemas.\n", + error->message); + + return g_settings_schema_source_ref(default_source); + } + + if (!schemas_source_verify(default_source, reference_source, &error)) { + g_printerr("Installed schemas failed verification: %s\n" + "Falling back to built-in reference schemas.\n", + error->message); + + return reference_source; /* transfer */ + } + + /* Installed schemas verified; use them. */ + g_settings_schema_source_unref(reference_source); + return g_settings_schema_source_ref(default_source); +} // BEGIN copied from glib/gio/gsettingsbackend.c @@ -354,3 +829,5 @@ terminal_g_settings_backend_sync(GSettingsBackend* backend) } // END copied from glib + +#endif /* TERMINAL_SERVER || TERMINAL_PREFERENCES */ diff --git a/src/terminal-settings-utils.hh b/src/terminal-settings-utils.hh index a64712b9..90ca6256 100644 --- a/src/terminal-settings-utils.hh +++ b/src/terminal-settings-utils.hh @@ -1,4 +1,41 @@ /* + * Copyright © 2008, 2010, 2022 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <gio/gio.h> +#include <gio/gsettingsbackend.h> + +GSettings* terminal_g_settings_new (GSettingsBackend* backend, + GSettingsSchemaSource* source, + char const* schema_id); + +GSettings* terminal_g_settings_new_with_path (GSettingsBackend* backend, + GSettingsSchemaSource* source, + char const* schema_id, + char const* path); + +GSettingsSchemaSource* terminal_g_settings_schema_source_get_default(void); + +GTree* terminal_g_settings_backend_create_tree(void); + +// BEGIN copied from glib/gio/gsettingsbackendinternal.h + +/* * Copyright © 2009, 2010 Codethink Limited * Copyright © 2010 Red Hat, Inc. * @@ -19,12 +56,6 @@ * Matthias Clasen <mclasen@redhat.com> */ -#pragma once - -#include <gio/gsettingsbackend.h> - -GTree* terminal_g_settings_backend_create_tree(void); - GPermission* terminal_g_settings_backend_get_permission(GSettingsBackend* backend, char const*path); @@ -58,5 +89,7 @@ gboolean terminal_g_settings_backend_write(GSettingsBackend* backend, void* origin_tag); gboolean terminal_g_settings_backend_write_tree(GSettingsBackend* backend, - GTree*tree, - void* origin_tag); + GTree* tree, + void* origin_tag); + +// END copied from glib diff --git a/src/terminal-util.cc b/src/terminal-util.cc index 36554315..b430efca 100644 --- a/src/terminal-util.cc +++ b/src/terminal-util.cc @@ -1570,380 +1570,3 @@ terminal_util_check_envv(char const* const* strv) return TRUE; } - -#define TERMINAL_SCHEMA_VERIFIER_ERROR (g_quark_from_static_string("TerminalSchemaVerifier")) - -typedef enum { - TERMINAL_SCHEMA_VERIFIER_SCHEMA_MISSING, - TERMINAL_SCHEMA_VERIFIER_SCHEMA_PATH, - TERMINAL_SCHEMA_VERIFIER_KEY_MISSING, - TERMINAL_SCHEMA_VERIFIER_KEY_TYPE, - TERMINAL_SCHEMA_VERIFIER_KEY_DEFAULT, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_UNKNOWN, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_MISMATCH, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_ENUM_VALUE, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_INTERVAL, - TERMINAL_SCHEMA_VERIFIER_CHILD_MISSING, -} TerminalSchemaVerifierError; - -static gboolean -strv_contains(char const* const* strv, - char const* str) -{ - if (strv == nullptr) - return FALSE; - - for (size_t i = 0; strv[i]; i++) { - if (g_str_equal (strv[i], str)) - return TRUE; - } - - return FALSE; -} - -static gboolean -schema_key_range_compatible(GSettingsSchema* source_schema, - GSettingsSchemaKey* source_key, - char const* key, - GSettingsSchemaKey* reference_key, - GError** error) -{ - gs_unref_variant GVariant* source_range = - g_settings_schema_key_get_range(source_key); - gs_unref_variant GVariant* reference_range = - g_settings_schema_key_get_range(reference_key); - - char const* source_type = nullptr; - gs_unref_variant GVariant* source_data = nullptr; - g_variant_get(source_range, "(&sv)", &source_type, &source_data); - - char const* reference_type = nullptr; - gs_unref_variant GVariant* reference_data = nullptr; - g_variant_get(reference_range, "(&sv)", &reference_type, &reference_data); - - if (!g_str_equal(source_type, reference_type)) { - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE, - "Schema \"%s\" key \"%s\" has range type \"%s\" but reference range type is \"%s\"", - g_settings_schema_get_id(source_schema), - key, source_type, reference_type); - return FALSE; - } - - if (g_str_equal(reference_type, "type")) - ; /* no constraints; this is fine */ - else if (g_str_equal(reference_type, "enum")) { - size_t source_values_len = 0; - gs_free char const** source_values = g_variant_get_strv(source_data, &source_values_len); - - size_t reference_values_len = 0; - gs_free char const** reference_values = g_variant_get_strv(reference_data, &reference_values_len); - - /* Check that every enum value in source is valid according to the reference */ - for (size_t i = 0; i < source_values_len; ++i) { - if (!strv_contains(reference_values, source_values[i])) { - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_ENUM_VALUE, - "Schema \"%s\" key \"%s\" has enum value \"%s\" not in reference schema", - g_settings_schema_get_id(source_schema), - key, source_values[i]); - return FALSE; - } - } - } else if (g_str_equal(reference_type, "flags")) { - /* Our schemas don't use flags. If that changes, need to implement this! */ - g_assert_not_reached(); - } else if (g_str_equal(reference_type, "range")) { - if (!g_variant_is_of_type(source_data, - g_variant_get_type(reference_data))) { - char const* source_type_str = g_variant_get_type_string(source_data); - char const* reference_type_str = g_variant_get_type_string(reference_data); - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_MISMATCH, - "Schema \"%s\" key \"%s\" has range type \"%s\" but reference range type is \"%s\"", - g_settings_schema_get_id(source_schema), - key, source_type_str, reference_type_str); - return FALSE; - } - - gs_unref_variant GVariant* reference_min = nullptr; - gs_unref_variant GVariant* reference_max = nullptr; - g_variant_get(reference_data, "(**)", &reference_min, &reference_max); - - gs_unref_variant GVariant* source_min = nullptr; - gs_unref_variant GVariant* source_max = nullptr; - g_variant_get(source_data, "(**)", &source_min, &source_max); - - /* The source interval must be contained within the reference interval */ - if (g_variant_compare(source_min, reference_min) < 0 || - g_variant_compare(source_max, reference_max) > 0) { - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_INTERVAL, - "Schema \"%s\" key \"%s\" has range interval not contained in reference range interval", - g_settings_schema_get_id(source_schema), key); - return FALSE; - } - } else { - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_KEY_RANGE_TYPE_UNKNOWN, - "Schema \"%s\" key \"%s\" has unknown range type \"%s\"", - g_settings_schema_get_id(source_schema), - key, reference_type); - return FALSE; - } - - return TRUE; -} - -static gboolean -schema_verify_key(GSettingsSchema* source_schema, - char const* key, - GSettingsSchema* reference_schema, - GError** error) -{ - if (!g_settings_schema_has_key(source_schema, key)) { - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_KEY_MISSING, - "Schema \"%s\" has missing key \"%s\"", - g_settings_schema_get_id(source_schema), key); - return FALSE; - } - - gs_unref_settings_schema_key GSettingsSchemaKey* source_key = - g_settings_schema_get_key(source_schema, key); - g_assert_nonnull(source_key); - - gs_unref_settings_schema_key GSettingsSchemaKey* reference_key = - g_settings_schema_get_key(reference_schema, key); - g_assert_nonnull(reference_key); - - GVariantType const* source_type = g_settings_schema_key_get_value_type(source_key); - GVariantType const* reference_type = g_settings_schema_key_get_value_type(reference_key); - if (!g_variant_type_equal(source_type, reference_type)) { - gs_free char* source_type_str = g_variant_type_dup_string(source_type); - gs_free char* reference_type_str = g_variant_type_dup_string(reference_type); - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_KEY_TYPE, - "Schema \"%s\" has type \"%s\" but reference type is \"%s\"", - g_settings_schema_get_id(source_schema), - source_type_str, reference_type_str); - return FALSE; - } - - gs_unref_variant GVariant* source_default = g_settings_schema_key_get_default_value(source_key); - if (!g_settings_schema_key_range_check(reference_key, source_default)) { - gs_free char* source_value_str = g_variant_print(source_default, TRUE); - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_KEY_DEFAULT, - "Schema \"%s\" default value \"%s\" does not conform to reference schema", - g_settings_schema_get_id(source_schema), source_value_str); - return FALSE; - } - - if (!schema_key_range_compatible(source_schema, - source_key, - key, - reference_key, - error)) - return FALSE; - - return TRUE; -} - -static gboolean -schema_verify_child(GSettingsSchema* source_schema, - char const* child_name, - GSettingsSchema* reference_schema, - GError** error) -{ - /* Should verify the child's schema ID is as expected and exists in - * the source, but there appears to be no API to get the schema ID of - * the child. - * - * We work around this missing verification by never calling - * g_settings_get_child() and instead always constructing the child - * GSettings directly; and the existence and correctness of that - * schema is verified by the per-schema checks. - */ - - return TRUE; -} - -static gboolean -schema_verify(GSettingsSchema* source_schema, - GSettingsSchema* reference_schema, - GError** error) -{ - /* Verify path */ - char const* source_path = g_settings_schema_get_path(source_schema); - char const* reference_path = g_settings_schema_get_path(reference_schema); - if (g_strcmp0(source_path, reference_path) != 0) { - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_SCHEMA_PATH, - "Schema \"%s\" has path \"%s\" but reference path is \"%s\"", - g_settings_schema_get_id(source_schema), - source_path ? source_path : "(null)", - reference_path ? reference_path : "(null)"); - return FALSE; - } - - /* Verify keys */ - gs_strfreev char** keys = g_settings_schema_list_keys(reference_schema); - if (keys) { - for (int i = 0; keys[i]; ++i) { - if (!schema_verify_key(source_schema, - keys[i], - reference_schema, - error)) - return FALSE; - } - } - - /* Verify child schemas */ - gs_strfreev char** source_children = g_settings_schema_list_children(source_schema); - gs_strfreev char** reference_children = g_settings_schema_list_children(reference_schema); - if (reference_children) { - for (size_t i = 0; reference_children[i]; ++i) { - if (!strv_contains((char const* const*)source_children, reference_children[i])) { - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_CHILD_MISSING, - "Schema \"%s\" has missing child \"%s\"", - g_settings_schema_get_id(source_schema), - reference_children[i]); - return FALSE; - } - - if (!schema_verify_child(source_schema, - reference_children[i], - reference_schema, - error)) - return FALSE; - } - } - - return TRUE; -} - -static gboolean -schemas_source_verify_schema_by_name(GSettingsSchemaSource* source, - char const* schema_name, - GSettingsSchemaSource* reference_source, - GError** error) -{ - gs_unref_settings_schema GSettingsSchema* source_schema = - g_settings_schema_source_lookup(source, schema_name, TRUE /* recursive */); - - if (!source_schema) { - g_set_error(error, TERMINAL_SCHEMA_VERIFIER_ERROR, - TERMINAL_SCHEMA_VERIFIER_SCHEMA_MISSING, - "Schema \"%s\" is missing", schema_name); - return FALSE; - } - - gs_unref_settings_schema GSettingsSchema* reference_schema = - g_settings_schema_source_lookup(reference_source, - schema_name, - FALSE /* recursive */); - g_assert_nonnull(reference_schema); - - return schema_verify(source_schema, - reference_schema, - error); -} - -static gboolean -schemas_source_verify_schemas(GSettingsSchemaSource* source, - char const* const* schemas, - GSettingsSchemaSource* reference_source, - GError** error) -{ - if (!schemas) - return TRUE; - - for (int i = 0; schemas[i]; ++i) { - if (!schemas_source_verify_schema_by_name(source, - schemas[i], - reference_source, - error)) - return FALSE; - } - - return TRUE; -} - -static gboolean -schemas_source_verify(GSettingsSchemaSource* source, - GSettingsSchemaSource* reference_source, - GError** error) -{ - gs_strfreev char** reloc_schemas = nullptr; - gs_strfreev char** nonreloc_schemas = nullptr; - - g_settings_schema_source_list_schemas(reference_source, - FALSE /* recursive */, - &reloc_schemas, - &nonreloc_schemas); - - if (!schemas_source_verify_schemas(source, - (char const* const*)reloc_schemas, - reference_source, - error)) - return FALSE; - - if (!schemas_source_verify_schemas(source, - (char const* const*)nonreloc_schemas, - reference_source, - error)) - return FALSE; - - return TRUE; -} - - -GSettingsSchemaSource* -terminal_g_settings_schema_source_get_default(void) -{ - GSettingsSchemaSource* default_source = g_settings_schema_source_get_default(); - - gs_free auto schema_dir = - terminal_client_get_directory_uninstalled( -#if defined(TERMINAL_SERVER) - TERM_LIBEXECDIR, -#elif defined(TERMINAL_PREFERENCES) - TERM_PKGLIBDIR, -#else -#error Need to define installed location -#endif - TERM_PKGLIBDIR, - "gschemas.compiled", - GFileTest(0)); - - gs_free_error GError* error = nullptr; - GSettingsSchemaSource* reference_source = - g_settings_schema_source_new_from_directory(schema_dir, - nullptr /* parent source */, - FALSE /* trusted */, - &error); - if (!reference_source) { - /* Can only use the installed schemas, or abort here. */ - g_printerr("Failed to load reference schemas: %s\n" - "Using unverified installed schemas.\n", - error->message); - - return g_settings_schema_source_ref(default_source); - } - - if (!schemas_source_verify(default_source, reference_source, &error)) { - g_printerr("Installed schemas failed verification: %s\n" - "Falling back to built-in reference schemas.\n", - error->message); - - return reference_source; /* transfer */ - } - - /* Installed schemas verified; use them. */ - g_settings_schema_source_unref(reference_source); - return g_settings_schema_source_ref(default_source); -} diff --git a/src/terminal-util.hh b/src/terminal-util.hh index f4b7292b..d980725e 100644 --- a/src/terminal-util.hh +++ b/src/terminal-util.hh @@ -71,8 +71,6 @@ char **terminal_util_get_etc_shells (void); gboolean terminal_util_get_is_shell (const char *command); -GSettingsSchemaSource* terminal_g_settings_schema_source_get_default(void); - const GdkRGBA *terminal_g_settings_get_rgba (GSettings *settings, const char *key, GdkRGBA *rgba); |