summaryrefslogtreecommitdiff
path: root/stc/stcmonitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'stc/stcmonitor.c')
-rw-r--r--stc/stcmonitor.c627
1 files changed, 353 insertions, 274 deletions
diff --git a/stc/stcmonitor.c b/stc/stcmonitor.c
index db17251..c38d254 100644
--- a/stc/stcmonitor.c
+++ b/stc/stcmonitor.c
@@ -31,6 +31,7 @@
#include "stcitem.h"
#include "stcmount.h"
#include "stcmountmonitor.h"
+#include "stcconfigerror.h"
/**
* SECTION:stcmonitor
@@ -58,14 +59,16 @@ struct _StcMonitor
GMainContext *context;
- StcErrorHandlerFunc error_handler_func;
- gpointer error_handler_user_data;
-
GList *items;
GHashTable *map_id_to_item;
GFileMonitor *conf_file_monitor;
GFileMonitor *conf_dir_monitor;
+
+ GList *config_errors;
+
+ gboolean invalidated;
+ GSource *refresh_config_source;
};
typedef struct _StcMonitorClass StcMonitorClass;
@@ -80,13 +83,8 @@ struct _StcMonitorClass
StcItem *item);
void (*item_changed) (StcMonitor *monitor,
StcItem *item);
-};
-enum
-{
- PROP_0,
- PROP_ERROR_HANDLER_FUNC,
- PROP_ERROR_HANDLER_USER_DATA
+ void (*config_reloaded) (StcMonitor *monitor);
};
enum
@@ -94,12 +92,15 @@ enum
ITEM_ADDED_SIGNAL,
ITEM_REMOVED_SIGNAL,
ITEM_CHANGED_SIGNAL,
+ CONFIG_RELOADED_SIGNAL,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
-static void stc_monitor_update (StcMonitor *monitor);
+static void stc_monitor_update_config (StcMonitor *monitor);
+static void stc_monitor_invalidate_config (StcMonitor *monitor);
+static void stc_monitor_ensure_config (StcMonitor *monitor);
static void on_uevent (GUdevClient *client,
const gchar *action,
@@ -126,18 +127,13 @@ static void on_conf_dir_monitor_changed (GFileMonitor *monitor,
GFileMonitorEvent event_type,
gpointer user_data);
-static void
-stc_monitor_emit_gerror (StcMonitor *monitor,
- const gchar *filename,
- guint line_no,
- GError *error);
-
-static void stc_monitor_emit_stc_error (StcMonitor *monitor,
- const gchar *filename,
- guint line_no,
- gint error_code,
- const gchar *format,
- ...) G_GNUC_PRINTF(5, 6);
+static void append_config_error (GList **list,
+ const gchar *item_id,
+ const gchar *filename,
+ gint line_number,
+ StcConfigErrorSeverity severity,
+ const gchar *message_format,
+ ...) G_GNUC_PRINTF(6, 7);
G_DEFINE_TYPE (StcMonitor, stc_monitor, G_TYPE_OBJECT);
@@ -146,6 +142,12 @@ stc_monitor_finalize (GObject *object)
{
StcMonitor *monitor = STC_MONITOR (object);
+ if (monitor->refresh_config_source != NULL)
+ {
+ g_source_destroy (monitor->refresh_config_source);
+ monitor->refresh_config_source = NULL;
+ }
+
g_signal_handlers_disconnect_by_func (monitor->gudev_client,
G_CALLBACK (on_uevent),
monitor);
@@ -182,54 +184,6 @@ stc_monitor_finalize (GObject *object)
}
static void
-stc_monitor_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- StcMonitor *monitor = STC_MONITOR (object);
-
- switch (prop_id)
- {
- case PROP_ERROR_HANDLER_FUNC:
- g_value_set_pointer (value, monitor->error_handler_func);
- break;
-
- case PROP_ERROR_HANDLER_USER_DATA:
- g_value_set_pointer (value, monitor->error_handler_user_data);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-stc_monitor_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- StcMonitor *monitor = STC_MONITOR (object);
-
- switch (prop_id)
- {
- case PROP_ERROR_HANDLER_FUNC:
- monitor->error_handler_func = g_value_get_pointer (value);
- break;
-
- case PROP_ERROR_HANDLER_USER_DATA:
- monitor->error_handler_user_data = g_value_get_pointer (value);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
stc_monitor_init (StcMonitor *monitor)
{
monitor->context = g_main_context_get_thread_default ();
@@ -261,10 +215,8 @@ stc_monitor_constructed (GObject *object)
g_file_monitor_set_rate_limit (monitor->conf_file_monitor, 50);
if (monitor->conf_file_monitor == NULL)
{
- stc_monitor_emit_gerror (monitor,
- path,
- -1,
- error);
+ /* use g_warning() since it indicates an installation problem if the stc.conf file is missing */
+ g_warning ("Cannot monitor file %s: %s", path, error->message);
g_error_free (error);
}
g_signal_connect (monitor->conf_file_monitor,
@@ -281,10 +233,8 @@ stc_monitor_constructed (GObject *object)
g_file_monitor_set_rate_limit (monitor->conf_dir_monitor, 50);
if (monitor->conf_dir_monitor == NULL)
{
- stc_monitor_emit_gerror (monitor,
- path,
- -1,
- error);
+ /* use g_warning() since it indicates an installation problem if the stc.conf file is missing */
+ g_warning ("Cannot monitor directory %s: %s", path, error->message);
g_error_free (error);
}
g_signal_connect (monitor->conf_dir_monitor,
@@ -310,7 +260,8 @@ stc_monitor_constructed (GObject *object)
G_CALLBACK (on_mount_removed),
monitor);
- stc_monitor_update (monitor);
+ /* initial coldplug */
+ stc_monitor_update_config (monitor);
if (G_OBJECT_CLASS (stc_monitor_parent_class)->constructed)
G_OBJECT_CLASS (stc_monitor_parent_class)->constructed (object);
@@ -324,39 +275,6 @@ stc_monitor_class_init (StcMonitorClass *klass)
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = stc_monitor_finalize;
gobject_class->constructed = stc_monitor_constructed;
- gobject_class->get_property = stc_monitor_get_property;
- gobject_class->set_property = stc_monitor_set_property;
-
- /**
- * StcMonitor:error-handler-func:
- *
- * Pointer to a #StcErrorHandlerFunc to call on error, or %NULL.
- */
- g_object_class_install_property (gobject_class,
- PROP_ERROR_HANDLER_FUNC,
- g_param_spec_pointer ("error-handler-func",
- "Error handler function",
- "Function to call on errors",
- G_PARAM_READABLE |
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- /**
- * StcMonitor:error-handler-user-data:
- *
- * User-data to pass to the function pointer defined in the #StcMonitor:error-handler-func property.
- */
- g_object_class_install_property (gobject_class,
- PROP_ERROR_HANDLER_USER_DATA,
- g_param_spec_pointer ("error-handler-user-data",
- "Error handler user data",
- "Error handler user data",
- G_PARAM_READABLE |
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
/**
* StcMonitor::item-added:
@@ -399,7 +317,8 @@ stc_monitor_class_init (StcMonitorClass *klass)
* @monitor: The #StcMonitor emitting the signal.
* @item: The item that changed.
*
- * Emitted when an item changes.
+ * Emitted when an item changes (either the configuration of item or
+ * the state of the item).
*/
signals[ITEM_CHANGED_SIGNAL] = g_signal_new ("item-changed",
G_TYPE_FROM_CLASS (klass),
@@ -411,28 +330,36 @@ stc_monitor_class_init (StcMonitorClass *klass)
G_TYPE_NONE,
1,
STC_TYPE_ITEM);
+
+ /**
+ * StcMonitor::config-reloaded:
+ * @monitor: The #StcMonitor emitting the signal.
+ *
+ * Emitted when the configuration files has been reloaded.
+ */
+ signals[CONFIG_RELOADED_SIGNAL] = g_signal_new ("config-reloaded",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (StcMonitorClass, config_reloaded),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
}
/**
* stc_monitor_new:
- * @error_handler_func: A function to handle errors or %NULL.
- * @error_handler_user_data: The @user_data #gpointer to pass to @error_handler_func.
*
- * Creates a new #StcMonitor that reads configuration files from the
- * default configuration directory
- * (e.g. <filename>/etc</filename>).
+ * Creates a new #StcMonitor.
*
* Returns: A #StcMonitor. Free with g_object_unref().
*/
StcMonitor *
-stc_monitor_new (StcErrorHandlerFunc error_handler_func,
- gpointer error_handler_user_data)
+stc_monitor_new (void)
{
StcMonitor *monitor;
- monitor = STC_MONITOR (g_object_new (STC_TYPE_MONITOR,
- "error-handler-func", error_handler_func,
- "error-handler-user-data", error_handler_user_data,
- NULL));
+ monitor = STC_MONITOR (g_object_new (STC_TYPE_MONITOR, NULL));
return monitor;
}
@@ -453,6 +380,8 @@ stc_monitor_get_items (StcMonitor *monitor)
g_return_val_if_fail (STC_IS_MONITOR (monitor), NULL);
+ stc_monitor_ensure_config (monitor);
+
ret = g_list_copy (monitor->items);
g_list_foreach (ret, (GFunc) g_object_ref, NULL);
@@ -522,7 +451,8 @@ check_validity (StcMonitor *monitor,
StcItemType item_type,
GHashTable *options,
const gchar *path,
- gint line_no)
+ gint line_no,
+ GList **config_errors)
{
gboolean ret;
@@ -535,22 +465,22 @@ check_validity (StcMonitor *monitor,
g_hash_table_lookup (options, "FilesystemUUID") != NULL ||
g_hash_table_lookup (options, "FilesystemLabel") != NULL))
{
- stc_monitor_emit_stc_error (monitor,
- path,
- line_no,
- STC_ERROR_FAILED,
- "Filesystem item %s needs one of FilesystemDevice, FilesystemUUID and FilesystemLabel options set.",
- item_id);
+ append_config_error (config_errors,
+ item_id,
+ path,
+ line_no,
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "Filesystem item needs one of FilesystemDevice, FilesystemUUID and FilesystemLabel options set");
goto out;
}
if (g_hash_table_lookup (options, "FilesystemMountPath") == NULL)
{
- stc_monitor_emit_stc_error (monitor,
- path,
- line_no,
- STC_ERROR_INSUFFICIENT_DATA,
- "Filesystem item %s is missing option FilesystemMountPath.",
- item_id);
+ append_config_error (config_errors,
+ item_id,
+ path,
+ line_no,
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "Filesystem item is missing option FilesystemMountPath");
goto out;
}
break;
@@ -559,12 +489,12 @@ check_validity (StcMonitor *monitor,
if (!(g_hash_table_lookup (options, "RaidUUID") != NULL ||
g_hash_table_lookup (options, "RaidName") != NULL))
{
- stc_monitor_emit_stc_error (monitor,
- path,
- line_no,
- STC_ERROR_FAILED,
- "Raid item %s needs one of RaidUUID and RaidName options set.",
- item_id);
+ append_config_error (config_errors,
+ item_id,
+ path,
+ line_no,
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "Raid item needs one of RaidUUID and RaidName options set");
goto out;
}
break;
@@ -572,23 +502,18 @@ check_validity (StcMonitor *monitor,
case STC_ITEM_TYPE_LUKS:
if (!(g_hash_table_lookup (options, "LuksUUID") != NULL))
{
- stc_monitor_emit_stc_error (monitor,
- path,
- line_no,
- STC_ERROR_FAILED,
- "Luks item %s needs the LuksUUID option set.",
- item_id);
+ append_config_error (config_errors,
+ item_id,
+ path,
+ line_no,
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "Luks item needs the LuksUUID option set");
goto out;
}
break;
default:
- stc_monitor_emit_stc_error (monitor,
- path,
- line_no,
- STC_ERROR_FAILED,
- "Unsupported item type %d.",
- item_type);
+ g_assert_not_reached ();
goto out;
}
@@ -601,21 +526,33 @@ check_validity (StcMonitor *monitor,
static GList *
stc_monitor_load_one_file (StcMonitor *monitor,
const gchar *path,
- GError **error)
+ GList **config_errors)
{
GList *ret;
GKeyFile *key_file;
gchar **groups;
guint n, m;
gboolean failed;
+ GError *error;
ret = NULL;
groups = NULL;
failed = TRUE;
key_file = g_key_file_new ();
- if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, error))
- goto out;
+ error = NULL;
+ if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error))
+ {
+ append_config_error (config_errors,
+ NULL,
+ path,
+ -1,
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "Error parsing key/value file: %s",
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
groups = g_key_file_get_groups (key_file, NULL);
for (n = 0; groups != NULL && groups[n] != NULL; n++)
@@ -631,7 +568,6 @@ stc_monitor_load_one_file (StcMonitor *monitor,
gchar **depends_strv;
const gchar *item_type_as_string;
gchar **keys;
- GError *local_error;
gboolean auto_val;
tokens = NULL;
@@ -643,25 +579,27 @@ stc_monitor_load_one_file (StcMonitor *monitor,
tokens = g_strsplit (group, " ", 0);
if (g_strv_length (tokens) != 2)
{
- stc_monitor_emit_stc_error (monitor,
- path,
- -1,
- STC_ERROR_PARSE_ERROR,
- "Error parsing group name `%s'",
- group);
+ append_config_error (config_errors,
+ NULL,
+ path,
+ -1,
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "Error parsing group name `%s'. Expected two tokens, found %d",
+ group, g_strv_length (tokens));
goto process_next_item;
}
item_type = item_type_from_string (tokens[0]);
if (item_type == STC_ITEM_TYPE_INVALID)
{
- stc_monitor_emit_stc_error (monitor,
- path,
- -1,
- STC_ERROR_PARSE_ERROR,
- "Error parsing item type `%s' in group `%s'",
- tokens[0],
- group);
+ append_config_error (config_errors,
+ NULL,
+ path,
+ -1,
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "Unrecognized item type %s in group `%s'",
+ tokens[0],
+ group);
goto process_next_item;
}
item_type_as_string = tokens[0];
@@ -669,14 +607,15 @@ stc_monitor_load_one_file (StcMonitor *monitor,
item_id = tokens[1];
if (!is_valid_item_id (item_id))
{
- stc_monitor_emit_stc_error (monitor,
- path,
- -1,
- STC_ERROR_PARSE_ERROR,
- "Invalid item identifer `%s' in group `%s'. "
- "Only characters in [a-zA-Z0-9_] are supported.",
- item_id,
- group);
+ append_config_error (config_errors,
+ NULL,
+ path,
+ -1,
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "Invalid item identifer %s in group `%s'. "
+ "Only characters in [a-zA-Z0-9_] are supported",
+ item_id,
+ group);
goto process_next_item;
}
@@ -704,23 +643,22 @@ stc_monitor_load_one_file (StcMonitor *monitor,
comment = g_key_file_get_string (key_file, group, "Comment", NULL);
/* Auto is optional (but we want to complain if set to an invalid value e.g. 'True') */
- local_error = NULL;
- auto_val = g_key_file_get_boolean (key_file, group, "Auto", &local_error);
- if (local_error != NULL)
+ error = NULL;
+ auto_val = g_key_file_get_boolean (key_file, group, "Auto", &error);
+ if (error != NULL)
{
- if (local_error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
+ if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
{
- stc_monitor_emit_stc_error (monitor,
- path,
- -1,
- STC_ERROR_PARSE_ERROR,
- "Error parsing key Auto for item %s of type %s: %s",
- item_id,
- tokens[0],
- local_error->message);
+ append_config_error (config_errors,
+ item_id,
+ path,
+ -1,
+ STC_CONFIG_ERROR_SEVERITY_WARNING,
+ "Error parsing key Auto: %s",
+ error->message);
}
/* not fatal, just continue */
- g_error_free (local_error);
+ g_error_free (error);
}
/* Depends is optional */
@@ -732,7 +670,8 @@ stc_monitor_load_one_file (StcMonitor *monitor,
item_type,
options,
path,
- -1))
+ -1,
+ config_errors))
{
goto process_next_item;
}
@@ -778,29 +717,49 @@ stc_monitor_load_one_file (StcMonitor *monitor,
return ret;
}
-static GList *
-stc_monitor_load_one_file_emit_error (StcMonitor *monitor,
- const gchar *path)
+static void
+diff_sorted_lists (GList *list1,
+ GList *list2,
+ GCompareFunc compare,
+ GList **added,
+ GList **removed)
{
- GError *error;
- GList *ret;
+ int order;
- error = NULL;
- ret = stc_monitor_load_one_file (monitor, path, &error);
- if (error != NULL)
+ *added = *removed = NULL;
+
+ while (list1 != NULL && list2 != NULL)
{
- g_assert (ret == NULL);
- stc_monitor_emit_gerror (monitor,
- path,
- -1,
- error);
- g_error_free (error);
+ order = (*compare) (list1->data, list2->data);
+ if (order < 0)
+ {
+ *removed = g_list_prepend (*removed, list1->data);
+ list1 = list1->next;
+ }
+ else if (order > 0)
+ {
+ *added = g_list_prepend (*added, list2->data);
+ list2 = list2->next;
+ }
+ else
+ { /* same item */
+ list1 = list1->next;
+ list2 = list2->next;
+ }
}
- return ret;
+ while (list1 != NULL)
+ {
+ *removed = g_list_prepend (*removed, list1->data);
+ list1 = list1->next;
+ }
+ while (list2 != NULL)
+ {
+ *added = g_list_prepend (*added, list2->data);
+ list2 = list2->next;
+ }
}
-
static gint
_p_strcmp (gconstpointer a, gconstpointer b)
{
@@ -814,7 +773,8 @@ _p_strcmp (gconstpointer a, gconstpointer b)
}
static GList *
-stc_monitor_load_all_files (StcMonitor *monitor)
+stc_monitor_load_all_files (StcMonitor *monitor,
+ GList **out_config_errors)
{
gchar *path;
gchar *dir_path;
@@ -829,8 +789,10 @@ stc_monitor_load_all_files (StcMonitor *monitor)
GList *ll;
GPtrArray *paths;
const gchar *const *deps;
+ GList *config_errors;
ret = NULL;
+ config_errors = NULL;
/* hash used to weed out duplicates and check deps */
id_to_item = g_hash_table_new (g_str_hash, g_str_equal);
@@ -842,10 +804,13 @@ stc_monitor_load_all_files (StcMonitor *monitor)
dir = g_dir_open (dir_path, 0, &error);
if (error != NULL)
{
- stc_monitor_emit_gerror (monitor,
- dir_path,
- -1,
- error);
+ append_config_error (&config_errors,
+ NULL,
+ dir_path,
+ -1,
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "%s",
+ error->message);
g_error_free (error);
}
else
@@ -866,7 +831,7 @@ stc_monitor_load_all_files (StcMonitor *monitor)
for (n = 0; n < paths->len; n++)
{
- loaded_items = stc_monitor_load_one_file_emit_error (monitor, paths->pdata[n]);
+ loaded_items = stc_monitor_load_one_file (monitor, paths->pdata[n], &config_errors);
for (l = loaded_items; l != NULL; l = l->next)
{
StcItem *item;
@@ -877,12 +842,12 @@ stc_monitor_load_all_files (StcMonitor *monitor)
id = stc_item_get_id (item);
if ((duplicate_item = g_hash_table_lookup (id_to_item, id)) != NULL)
{
- stc_monitor_emit_stc_error (monitor,
- _stc_item_get_path (item),
- _stc_item_get_line_no (item),
- STC_ERROR_DUPLICATE_ITEM,
- "Encountered item with duplicate id `%s'. Ignoring previous items.",
- id);
+ append_config_error (&config_errors,
+ id,
+ _stc_item_get_path (item),
+ _stc_item_get_line_no (item),
+ STC_CONFIG_ERROR_SEVERITY_ERROR,
+ "Encountered item with duplicate id. Ignoring previous item");
g_assert (g_list_find (ret, duplicate_item) != NULL);
ret = g_list_remove (ret, duplicate_item);
}
@@ -913,14 +878,14 @@ stc_monitor_load_all_files (StcMonitor *monitor)
dep_item = g_hash_table_lookup (id_to_item, dep_id);
if (dep_item == NULL)
{
- stc_monitor_emit_stc_error (monitor,
- _stc_item_get_path (item),
- _stc_item_get_line_no (item),
- STC_ERROR_UNRESOLVED_DEPENDENCY,
- "Item %s has unresolved dependency %s.",
- id,
- dep_id);
- /* don't remove the item */
+ append_config_error (&config_errors,
+ id,
+ _stc_item_get_path (item),
+ _stc_item_get_line_no (item),
+ STC_CONFIG_ERROR_SEVERITY_WARNING,
+ "Item has unresolved dependency on non-existing item %s",
+ dep_id);
+ /* Not fatal - don't remove the item */
}
}
}
@@ -929,6 +894,15 @@ stc_monitor_load_all_files (StcMonitor *monitor)
ret = g_list_reverse (ret);
+ if (out_config_errors != NULL)
+ {
+ *out_config_errors = config_errors;
+ }
+ else
+ {
+ g_list_foreach (config_errors, (GFunc) stc_config_error_unref, NULL);
+ g_list_free (config_errors);
+ }
return ret;
}
@@ -946,7 +920,7 @@ _item_cmp_func (gconstpointer a,
}
static void
-stc_monitor_update (StcMonitor *monitor)
+stc_monitor_update_config (StcMonitor *monitor)
{
GList *loaded_items;
GList *l;
@@ -955,6 +929,9 @@ stc_monitor_update (StcMonitor *monitor)
GList *items_added;
GList *items_removed;
GHashTable *loaded_items_ids;
+ GList *config_errors;
+ GList *errors_added;
+ GList *errors_removed;
items_changed = NULL;
items_added = NULL;
@@ -963,7 +940,7 @@ stc_monitor_update (StcMonitor *monitor)
loaded_items_ids = g_hash_table_new (g_str_hash, g_str_equal);
/* add/change items */
- loaded_items = stc_monitor_load_all_files (monitor);
+ loaded_items = stc_monitor_load_all_files (monitor, &config_errors);
for (l = loaded_items; l != NULL; l = l->next)
{
StcItem *item = STC_ITEM (l->data);
@@ -1018,7 +995,36 @@ stc_monitor_update (StcMonitor *monitor)
_stc_item_update_state (item);
}
- /* emit signals only when our monitor object has been completely updated */
+ config_errors = g_list_sort (config_errors, (GCompareFunc) stc_config_error_compare);
+ diff_sorted_lists (monitor->config_errors,
+ config_errors,
+ (GCompareFunc) stc_config_error_compare,
+ &errors_added,
+ &errors_removed);
+ for (l = errors_removed; l != NULL; l = l->next)
+ {
+ StcConfigError *config_error = l->data;
+ g_assert (g_list_find (monitor->config_errors, config_error) != NULL);
+ monitor->config_errors = g_list_remove (monitor->config_errors, config_error);
+ stc_config_error_unref (config_error);
+ }
+ for (l = errors_added; l != NULL; l = l->next)
+ {
+ StcConfigError *config_error = l->data;
+ monitor->config_errors = g_list_prepend (monitor->config_errors, stc_config_error_ref (config_error));
+ }
+ g_list_foreach (config_errors, (GFunc) stc_config_error_unref, NULL);
+ g_list_free (config_errors);
+ g_list_free (errors_removed);
+ g_list_free (errors_added);
+ monitor->config_errors = g_list_sort (monitor->config_errors, (GCompareFunc) stc_config_error_compare);
+
+ /* emit signals only when our monitor object has been completely
+ * updated - otherwise we get infinit loops if someone is calling a
+ * method that calls ensure()
+ */
+ monitor->invalidated = FALSE;
+
for (l = items_removed; l != NULL; l = l->next)
{
StcItem *item = STC_ITEM (l->data);
@@ -1041,6 +1047,8 @@ stc_monitor_update (StcMonitor *monitor)
g_object_unref (item);
}
g_list_free (items_changed);
+
+ g_signal_emit (monitor, signals[CONFIG_RELOADED_SIGNAL], 0);
}
static void
@@ -1050,8 +1058,7 @@ on_conf_file_monitor_changed (GFileMonitor *monitor,
GFileMonitorEvent event_type,
gpointer user_data)
{
- /* TODO: this is a bit expensive since all config files are reloaded */
- stc_monitor_update (STC_MONITOR (user_data));
+ stc_monitor_invalidate_config (STC_MONITOR (user_data));
}
static void
@@ -1061,45 +1068,7 @@ on_conf_dir_monitor_changed (GFileMonitor *monitor,
GFileMonitorEvent event_type,
gpointer user_data)
{
- /* TODO: this is a bit expensive since all config files are reloaded */
- stc_monitor_update (STC_MONITOR (user_data));
-}
-
-static void
-stc_monitor_emit_gerror (StcMonitor *monitor,
- const gchar *filename,
- guint line_no,
- GError *error)
-{
- /* the following holds because all call-sites are guaranteed to be
- * in the correct context
- */
- g_assert (g_main_context_get_thread_default () == monitor->context);
-
- if (monitor->error_handler_func != NULL)
- monitor->error_handler_func (monitor, filename, line_no, error, monitor->error_handler_user_data);
-}
-
-static void
-stc_monitor_emit_stc_error (StcMonitor *monitor,
- const gchar *filename,
- guint line_no,
- gint error_code,
- const gchar *format,
- ...)
-{
- GError *error;
- va_list var_args;
-
- va_start (var_args, format);
- error = g_error_new_valist (STC_ERROR,
- error_code,
- format,
- var_args);
- va_end (var_args);
-
- stc_monitor_emit_gerror (monitor, filename, line_no, error);
- g_error_free (error);
+ stc_monitor_invalidate_config (STC_MONITOR (user_data));
}
GUdevClient *
@@ -1132,6 +1101,8 @@ on_uevent (GUdevClient *client,
monitor);
#endif
+ stc_monitor_ensure_config (monitor);
+
/* we don't really know what configuration items this applies to so
* we just update all of them
*/
@@ -1163,6 +1134,8 @@ on_mount_added (_StcMountMonitor *mount_monitor,
_stc_mount_get_mount_path (mount));
#endif
+ stc_monitor_ensure_config (monitor);
+
/* we don't really know what configuration items this applies to so
* we just update all of them
*/
@@ -1194,6 +1167,8 @@ on_mount_removed (_StcMountMonitor *mount_monitor,
_stc_mount_get_mount_path (mount));
#endif
+ stc_monitor_ensure_config (monitor);
+
/* we don't really know what configuration items this applies to so
* we just update all of them
*/
@@ -1208,3 +1183,107 @@ on_mount_removed (_StcMountMonitor *mount_monitor,
}
}
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * stc_monitor_get_config_errors:
+ * @monitor: A #StcMonitor.
+ *
+ * Gets the errors/warning detected when parsing configuration files.
+ *
+ * If reporting errors in a log file, you typically want to call this
+ * method at startup as well as every time the
+ * #StcMonitor::config-reloaded signal is emitted.
+ *
+ * Returns: A list of #StcConfigError structures. The returned list
+ * must be freed with g_list_free() after each element has been freed
+ * with stc_config_error_unref().
+ */
+GList *
+stc_monitor_get_config_errors (StcMonitor *monitor)
+{
+ GList *ret;
+
+ g_return_val_if_fail (STC_IS_MONITOR (monitor), NULL);
+
+ stc_monitor_ensure_config (monitor);
+
+ ret = g_list_copy (monitor->config_errors);
+ g_list_foreach (ret, (GFunc) stc_config_error_ref, NULL);
+
+ return ret;
+}
+
+static void
+append_config_error (GList **list,
+ const gchar *item_id,
+ const gchar *filename,
+ gint line_number,
+ StcConfigErrorSeverity severity,
+ const gchar *message_format,
+ ...)
+{
+ gchar *message;
+ va_list var_args;
+
+ va_start (var_args, message_format);
+ message = g_strdup_vprintf (message_format, var_args);
+ va_end (var_args);
+
+ *list = g_list_prepend (*list,
+ stc_config_error_new (item_id,
+ filename,
+ line_number,
+ severity,
+ message));
+ //g_debug ("message=`%s'", message);
+ g_free (message);
+}
+
+static gboolean
+stc_monitor_invalidate_config_on_refresh_timeout_cb (gpointer user_data)
+{
+ StcMonitor *monitor = STC_MONITOR (user_data);
+ //g_debug ("%s %d", G_STRFUNC, monitor->invalidated);
+ g_assert (monitor->refresh_config_source != NULL);
+ monitor->refresh_config_source = NULL;
+ if (monitor->invalidated)
+ stc_monitor_ensure_config (monitor);
+ return FALSE; /* remove the source */
+}
+
+static void
+stc_monitor_invalidate_config (StcMonitor *monitor)
+{
+ //g_debug ("%s %d", G_STRFUNC, monitor->invalidated);
+ if (!monitor->invalidated)
+ {
+ /* reload config items in at least two seconds */
+ g_assert (monitor->refresh_config_source == NULL);
+ monitor->refresh_config_source = g_timeout_source_new_seconds (2);
+ g_source_set_priority (monitor->refresh_config_source, G_PRIORITY_DEFAULT);
+ g_source_set_callback (monitor->refresh_config_source,
+ stc_monitor_invalidate_config_on_refresh_timeout_cb,
+ monitor,
+ NULL); /* GDestroyNotify */
+ g_source_attach (monitor->refresh_config_source, monitor->context);
+ g_source_unref (monitor->refresh_config_source);
+
+ monitor->invalidated = TRUE;
+ }
+ else
+ {
+ g_assert (monitor->refresh_config_source != NULL);
+ }
+}
+
+static void
+stc_monitor_ensure_config (StcMonitor *monitor)
+{
+ //g_debug ("%s %d", G_STRFUNC, monitor->invalidated);
+ if (monitor->invalidated)
+ {
+ stc_monitor_update_config (monitor);
+ }
+}
+