summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Van Assche <me@dylanvanassche.be>2022-12-30 12:55:38 +0100
committerDylan Van Assche <dylan.vanassche@ugent.be>2023-01-20 16:24:44 +0100
commitf73e023b8fadd46f2de21c5086d7fbea0e8d0d53 (patch)
treea9c6a722ce1eca3f0704ca5360b87b233126b8bd
parentcb66669cff959046c8ef02abe13fc4f1a68660c5 (diff)
downloadgeoclue-f73e023b8fadd46f2de21c5086d7fbea0e8d0d53.tar.gz
config: add support for conf.d style
Distros may want to overwrite various parameters of GeoClue's config file without shipping a complete config file which may result into out-of-sync config files when newer GeoClue versions are released. Support /etc/geoclue/conf.d/ as a config directory in which distros can place overwrites, the config files are loaded in alphabetic order and overwrite the original config file parameters stored in /etc/geoclue/geoclue.conf
-rw-r--r--src/gclue-config.c362
1 files changed, 263 insertions, 99 deletions
diff --git a/src/gclue-config.c b/src/gclue-config.c
index 2802484..2cafe24 100644
--- a/src/gclue-config.c
+++ b/src/gclue-config.c
@@ -22,10 +22,12 @@
#include <glib/gi18n.h>
#include <config.h>
+#include <string.h>
#include "gclue-config.h"
#define CONFIG_FILE_PATH SYSCONFDIR "/geoclue/geoclue.conf"
+#define CONFIG_D_DIRECTORY SYSCONFDIR "/geoclue/conf.d/"
/* This class will be responsible for fetching configuration. */
@@ -103,20 +105,29 @@ gclue_config_class_init (GClueConfigClass *klass)
}
static void
-load_agent_config (GClueConfig *config)
+load_agent_config (GClueConfig *config, gboolean initial)
{
GClueConfigPrivate *priv = config->priv;
g_autoptr(GError) error = NULL;
+ g_auto(GStrv) agents = NULL;
+ gsize num_agents;
- priv->agents = g_key_file_get_string_list (priv->key_file,
- "agent",
- "whitelist",
- &priv->num_agents,
- &error);
- if (error != NULL) {
- g_critical ("Failed to read 'agent/whitelist' key: %s",
- error->message);
- }
+ if (!initial && !g_key_file_has_key (priv->key_file, "agent", "whitelist", NULL))
+ return;
+
+ agents = g_key_file_get_string_list (priv->key_file,
+ "agent",
+ "whitelist",
+ &num_agents,
+ &error);
+ if (error == NULL) {
+ g_clear_pointer (&priv->agents, g_strfreev);
+ priv->agents = g_steal_pointer (&agents);
+ priv->num_agents = num_agents;
+
+ } else
+ g_warning ("Failed to read 'agent/whitelist' key: %s",
+ error->message);
}
static void
@@ -134,11 +145,16 @@ load_app_configs (GClueConfig *config)
return;
for (i = 0; i < num_groups; i++) {
- AppConfig *app_config;
- int* users;
+ AppConfig *app_config = NULL;
+ g_autofree int *users = NULL;
+ GList *node;
gsize num_users = 0, j;
gboolean allowed, system;
gboolean ignore = FALSE;
+ gboolean new_app_config = TRUE;
+ gboolean has_allowed = FALSE;
+ gboolean has_system = FALSE;
+ gboolean has_users = FALSE;
g_autoptr(GError) error = NULL;
for (j = 0; known_groups[j] != NULL; j++)
@@ -151,36 +167,64 @@ load_app_configs (GClueConfig *config)
if (ignore)
continue;
+ /* Check if entry is new or is overwritten */
+ for (node = priv->app_configs; node != NULL; node = node->next) {
+ if (strcmp (((AppConfig *) node->data)->id, groups[i]) == 0) {
+ app_config = (AppConfig *) node->data;
+ new_app_config = FALSE;
+
+ break;
+ }
+ }
+
allowed = g_key_file_get_boolean (priv->key_file,
groups[i],
"allowed",
&error);
- if (error != NULL)
+ has_allowed = (error == NULL);
+ if (error != NULL && new_app_config)
goto error_out;
+ g_clear_error (&error);
system = g_key_file_get_boolean (priv->key_file,
groups[i],
"system",
&error);
- if (error != NULL)
+ has_system = (error == NULL);
+ if (error != NULL && new_app_config)
goto error_out;
+ g_clear_error (&error);
users = g_key_file_get_integer_list (priv->key_file,
groups[i],
"users",
&num_users,
&error);
- if (error != NULL)
+ has_users = (error == NULL);
+ if (error != NULL && new_app_config)
goto error_out;
+ g_clear_error (&error);
- app_config = g_slice_new0 (AppConfig);
- app_config->id = g_strdup (groups[i]);
- app_config->allowed = allowed;
- app_config->system = system;
- app_config->users = users;
- app_config->num_users = num_users;
- priv->app_configs = g_list_prepend (priv->app_configs, app_config);
+ /* New app config, without erroring out above */
+ if (new_app_config) {
+ app_config = g_slice_new0 (AppConfig);
+ priv->app_configs = g_list_prepend (priv->app_configs, app_config);
+ app_config->id = g_strdup (groups[i]);
+ }
+
+ /* New app configs will have all of them, overwrites only some */
+ if (has_allowed)
+ app_config->allowed = allowed;
+
+ if (has_system)
+ app_config->system = system;
+
+ if (has_users) {
+ g_free (app_config->users);
+ app_config->users = g_steal_pointer (&users);
+ app_config->num_users = num_users;
+ }
continue;
error_out:
@@ -192,12 +236,18 @@ error_out:
static gboolean
load_enable_source_config (GClueConfig *config,
- const char *source_name)
+ const char *source_name,
+ gboolean initial,
+ gboolean enabled)
{
GClueConfigPrivate *priv = config->priv;
g_autoptr(GError) error = NULL;
gboolean enable;
+ /* Source should be initially enabled by default */
+ if (!g_key_file_has_key (priv->key_file, source_name, "enable", NULL))
+ return initial? TRUE: enabled;
+
enable = g_key_file_get_boolean (priv->key_file,
source_name,
"enable",
@@ -208,8 +258,8 @@ load_enable_source_config (GClueConfig *config,
source_name,
error->message);
- /* Source should be enabled by default */
- return TRUE;
+ /* Keep the previous enable state if something went wrong */
+ return enabled;
}
return enable;
@@ -220,137 +270,250 @@ load_enable_source_config (GClueConfig *config,
#define DEFAULT_WIFI_SUBMIT_NICK "geoclue"
static void
-load_wifi_config (GClueConfig *config)
+load_wifi_config (GClueConfig *config, gboolean initial)
{
GClueConfigPrivate *priv = config->priv;
g_autoptr(GError) error = NULL;
+ g_autofree char *wifi_url = NULL;
+ g_autofree char *wifi_submit_url = NULL;
+ g_autofree char *wifi_submit_nick = NULL;
+ guint wifi_submit_nick_length;
+
+ priv->enable_wifi_source =
+ load_enable_source_config (config, "wifi", initial,
+ priv->enable_wifi_source);
+
+ if (initial || g_key_file_has_key (priv->key_file, "wifi", "url", NULL)) {
+ wifi_url = g_key_file_get_string (priv->key_file,
+ "wifi",
+ "url",
+ &error);
+ if (error == NULL) {
+ g_clear_pointer (&priv->wifi_url, g_free);
+ priv->wifi_url = g_steal_pointer (&wifi_url);
+ } else if (initial) {
+ g_debug ("Using the default locate URL: %s", error->message);
+ g_clear_pointer (&priv->wifi_url, g_free);
+ priv->wifi_url = g_strdup (DEFAULT_WIFI_URL);
+ } else
+ g_warning ("Failed to get config \"wifi/url\": %s", error->message);
- priv->enable_wifi_source = load_enable_source_config (config, "wifi");
-
- priv->wifi_url = g_key_file_get_string (priv->key_file,
- "wifi",
- "url",
- &error);
- if (error != NULL) {
- g_debug ("Using the default locate URL: %s",
- error->message);
g_clear_error (&error);
- priv->wifi_url = g_strdup (DEFAULT_WIFI_URL);
}
- priv->wifi_submit = g_key_file_get_boolean (priv->key_file,
- "wifi",
- "submit-data",
- &error);
- if (error != NULL) {
- g_debug ("Failed to get config \"wifi/submit-data\": %s",
- error->message);
-
- return;
+ if (initial || g_key_file_has_key (priv->key_file, "wifi", "submit-data", NULL)) {
+ priv->wifi_submit = g_key_file_get_boolean (priv->key_file,
+ "wifi",
+ "submit-data",
+ &error);
+ if (error != NULL) {
+ g_warning ("Failed to get config \"wifi/submit-data\": %s",
+ error->message);
+ return;
+ }
+ g_clear_error (&error);
}
- priv->wifi_submit_url = g_key_file_get_string (priv->key_file,
- "wifi",
- "submission-url",
- &error);
- if (error != NULL) {
- g_debug ("Using the default submit URL: %s",
- error->message);
+ if (initial || g_key_file_has_key (priv->key_file, "wifi", "submission-url", NULL)) {
+ wifi_submit_url = g_key_file_get_string (priv->key_file,
+ "wifi",
+ "submission-url",
+ &error);
+
+ if (error == NULL) {
+ g_clear_pointer (&priv->wifi_submit_url, g_free);
+ priv->wifi_submit_url = g_steal_pointer (&wifi_submit_url);
+ } else if (initial) {
+ g_debug ("Using the default submission URL: %s", error->message);
+ g_clear_pointer (&priv->wifi_submit_url, g_free);
+ priv->wifi_submit_url = g_strdup (DEFAULT_WIFI_SUBMIT_URL);
+ } else
+ g_warning ("Failed to get config \"wifi/submission-url\": %s", error->message);
+
g_clear_error (&error);
- priv->wifi_submit_url = g_strdup (DEFAULT_WIFI_SUBMIT_URL);
}
- priv->wifi_submit_nick = g_key_file_get_string (priv->key_file,
- "wifi",
- "submission-nick",
- &error);
- if (error != NULL) {
- g_debug ("Using the default submission nick: %s",
- error->message);
- priv->wifi_submit_nick = g_strdup (DEFAULT_WIFI_SUBMIT_NICK);
+ if (initial || g_key_file_has_key (priv->key_file, "wifi", "submission-nick", NULL)) {
+ wifi_submit_nick = g_key_file_get_string (priv->key_file,
+ "wifi",
+ "submission-nick",
+ &error);
+
+ if (error == NULL) {
+ /* Submission nickname must be 2-32 characters long */
+ wifi_submit_nick_length = strlen (wifi_submit_nick);
+ if (wifi_submit_nick_length >= 2 && wifi_submit_nick_length <= 32) {
+ g_clear_pointer (&priv->wifi_submit_nick, g_free);
+ priv->wifi_submit_nick = g_steal_pointer (&wifi_submit_nick);
+ } else {
+ g_warning ("Submission nick must be between 2-32 characters long");
+
+ if (initial) {
+ g_debug ("Using the default submission nick: %s", error->message);
+ g_clear_pointer (&priv->wifi_submit_nick, g_free);
+ priv->wifi_submit_nick = g_strdup (DEFAULT_WIFI_SUBMIT_NICK);
+ }
+ }
+ } else if (initial) {
+ g_debug ("Using the default submission nick: %s", error->message);
+ g_clear_pointer (&priv->wifi_submit_nick, g_free);
+ priv->wifi_submit_nick = g_strdup (DEFAULT_WIFI_SUBMIT_NICK);
+ } else
+ g_warning ("Failed to get config \"wifi/submission-nick\": %s", error->message);
}
}
static void
-load_3g_config (GClueConfig *config)
+load_3g_config (GClueConfig *config, gboolean initial)
{
config->priv->enable_3g_source =
- load_enable_source_config (config, "3g");
+ load_enable_source_config (config, "3g", initial,
+ config->priv->enable_3g_source);
}
static void
-load_cdma_config (GClueConfig *config)
+load_cdma_config (GClueConfig *config, gboolean initial)
{
config->priv->enable_cdma_source =
- load_enable_source_config (config, "cdma");
+ load_enable_source_config (config, "cdma", initial,
+ config->priv->enable_cdma_source);
}
static void
-load_modem_gps_config (GClueConfig *config)
+load_modem_gps_config (GClueConfig *config, gboolean initial)
{
config->priv->enable_modem_gps_source =
- load_enable_source_config (config, "modem-gps");
+ load_enable_source_config (config, "modem-gps", initial,
+ config->priv->enable_modem_gps_source);
}
static void
-load_network_nmea_config (GClueConfig *config)
+load_network_nmea_config (GClueConfig *config, gboolean initial)
{
g_autoptr(GError) error = NULL;
+ g_autofree char* nmea_socket = NULL;
config->priv->enable_nmea_source =
- load_enable_source_config (config, "network-nmea");
- if (!config->priv->enable_nmea_source)
- return;
- config->priv->nmea_socket = g_key_file_get_string (config->priv->key_file,
- "network-nmea",
- "nmea-socket",
- &error);
- if (error != NULL) {
- g_debug ("`nmea-socket` configuration not set.");
+ load_enable_source_config (config, "network-nmea", initial,
+ config->priv->enable_nmea_source);
+
+ if (g_key_file_has_key (config->priv->key_file, "network-nmea", "nmea-socket", NULL)) {
+ nmea_socket = g_key_file_get_string (config->priv->key_file,
+ "network-nmea",
+ "nmea-socket",
+ &error);
+ if (error == NULL) {
+ g_clear_pointer (&config->priv->nmea_socket, g_free);
+ config->priv->nmea_socket = g_steal_pointer (&nmea_socket);
+ } else
+ g_warning ("Failed to get config \"nmea-socket\": %s", error->message);
}
}
static void
-load_compass_config (GClueConfig *config)
+load_compass_config (GClueConfig *config, gboolean initial)
{
config->priv->enable_compass =
- load_enable_source_config (config, "compass");
+ load_enable_source_config (config, "compass", initial,
+ config->priv->enable_compass);
}
static void
-load_static_source_config (GClueConfig *config)
+load_static_source_config (GClueConfig *config, gboolean initial)
{
config->priv->enable_static_source =
- load_enable_source_config (config, "static-source");
+ load_enable_source_config (config, "static-source", initial,
+ config->priv->enable_static_source);
}
static void
-gclue_config_init (GClueConfig *config)
-{
+load_config_file (GClueConfig *config, const char *path, gboolean initial) {
g_autoptr(GError) error = NULL;
- config->priv = gclue_config_get_instance_private(config);
- config->priv->key_file = g_key_file_new ();
+ g_debug ("Loading config: %s", path);
g_key_file_load_from_file (config->priv->key_file,
- CONFIG_FILE_PATH,
+ path,
0,
&error);
if (error != NULL) {
g_critical ("Failed to load configuration file '%s': %s",
- CONFIG_FILE_PATH, error->message);
-
+ path, error->message);
return;
}
- load_agent_config (config);
+ load_agent_config (config, initial);
load_app_configs (config);
- load_wifi_config (config);
- load_3g_config (config);
- load_cdma_config (config);
- load_modem_gps_config (config);
- load_network_nmea_config (config);
- load_compass_config (config);
- load_static_source_config (config);
+ load_wifi_config (config, initial);
+ load_3g_config (config, initial);
+ load_cdma_config (config, initial);
+ load_modem_gps_config (config, initial);
+ load_network_nmea_config (config, initial);
+ load_compass_config (config, initial);
+ load_static_source_config (config, initial);
+}
+
+static void
+files_element_clear (void *element)
+{
+ gchar **file_name = element;
+ g_free (*file_name);
+}
+
+static gint
+sort_files (gconstpointer a, gconstpointer b)
+{
+ char *str_a = *(char **)a;
+ char *str_b = *(char **)b;
+
+ return g_strcmp0 (str_a, str_b);
+}
+
+static void
+gclue_config_init (GClueConfig *config)
+{
+ g_autoptr(GDir) dir = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GArray) files = NULL;
+ char *name;
+ gsize i;
+
+ config->priv = gclue_config_get_instance_private (config);
+ config->priv->key_file = g_key_file_new ();
+
+ /* Load config file from default path, log all missing parameters */
+ load_config_file (config, CONFIG_FILE_PATH, TRUE);
+
+ /*
+ * Apply config overwrites from conf.d style config files,
+ * files are sorted alphabetically, example: '90-config.conf'
+ * will overwrite '50-config.conf'.
+ */
+ dir = g_dir_open (CONFIG_D_DIRECTORY, 0, &error);
+
+ if (error != NULL) {
+ g_warning ("Failed to open %s: %s",
+ CONFIG_D_DIRECTORY, error->message);
+ return;
+ }
+
+ files = g_array_new (FALSE, FALSE, sizeof(char *));
+ g_array_set_clear_func (files, files_element_clear);
+
+ while ((name = g_strdup (g_dir_read_name (dir)))) {
+ if (g_str_has_suffix (name, ".conf"))
+ g_array_append_val (files, name);
+ }
+
+ g_array_sort (files, sort_files);
+
+ for (i = 0; i < files->len; i++) {
+ g_autofree char *path = NULL;
+
+ path = g_build_filename (CONFIG_D_DIRECTORY,
+ g_array_index (files, char *, i),
+ NULL);
+ load_config_file (config, path, FALSE);
+ }
}
GClueConfig *
@@ -480,7 +643,7 @@ void
gclue_config_set_wifi_submit_nick (GClueConfig *config,
const char *nick)
{
-
+ g_clear_pointer (&config->priv->wifi_submit_nick, g_free);
config->priv->wifi_submit_nick = g_strdup (nick);
}
@@ -529,9 +692,10 @@ gclue_config_get_enable_nmea_source (GClueConfig *config)
void
gclue_config_set_nmea_socket (GClueConfig *config,
- const char *nmea_socket)
+ const char *nmea_socket)
{
- config->priv->nmea_socket = g_strdup(nmea_socket);
+ g_clear_pointer (&config->priv->nmea_socket, g_free);
+ config->priv->nmea_socket = g_strdup (nmea_socket);
}
gboolean