summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2010-10-11 10:31:33 -0400
committerDavid Zeuthen <davidz@redhat.com>2010-10-11 10:31:33 -0400
commit1417c1dcce3b6f107a338faa63d77248f710f354 (patch)
tree29c46dbac72b3a9f5b6dddb691e254691fa73fc3
parent7cb53e7dbbb420fb69e74944b701a40fc2cb411a (diff)
Change how config file errors are reportedHEADmaster
Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r--doc/stc-docs.xml1
-rw-r--r--doc/stc-sections.txt23
-rw-r--r--doc/stc.types1
-rw-r--r--stc/Makefile.am2
-rw-r--r--stc/stc.c75
-rw-r--r--stc/stc.h1
-rw-r--r--stc/stcconfigerror.c229
-rw-r--r--stc/stcconfigerror.h60
-rw-r--r--stc/stcd.c88
-rw-r--r--stc/stcenums.h14
-rw-r--r--stc/stcmonitor.c627
-rw-r--r--stc/stcmonitor.h24
-rw-r--r--stc/stctypes.h3
-rw-r--r--stc/test.c102
14 files changed, 875 insertions, 375 deletions
diff --git a/doc/stc-docs.xml b/doc/stc-docs.xml
index cd6addb..d023a6a 100644
--- a/doc/stc-docs.xml
+++ b/doc/stc-docs.xml
@@ -37,6 +37,7 @@
<xi:include href="xml/stcerror.xml"/>
<xi:include href="xml/stcitem.xml"/>
<xi:include href="xml/stcmonitor.xml"/>
+ <xi:include href="xml/stcconfigerror.xml"/>
<xi:include href="xml/stcoperation.xml"/>
</part>
diff --git a/doc/stc-sections.txt b/doc/stc-sections.txt
index 685f97f..5b853a7 100644
--- a/doc/stc-sections.txt
+++ b/doc/stc-sections.txt
@@ -2,10 +2,10 @@
<FILE>stcmonitor</FILE>
<TITLE>StcMonitor</TITLE>
StcMonitor
-StcErrorHandlerFunc
stc_monitor_new
stc_monitor_get_items
stc_monitor_get_item_by_id
+stc_monitor_get_config_errors
<SUBSECTION Standard>
STC_TYPE_MONITOR
STC_MONITOR
@@ -77,3 +77,24 @@ stc_error_quark
stc_error_get_type
STC_TYPE_ERROR
</SECTION>
+
+<SECTION>
+<FILE>stcconfigerror</FILE>
+<TITLE>StcConfigError</TITLE>
+StcConfigError
+StcConfigErrorSeverity
+stc_config_error_new
+stc_config_error_ref
+stc_config_error_unref
+stc_config_error_compare
+stc_config_error_get_item_id
+stc_config_error_get_filename
+stc_config_error_get_line_number
+stc_config_error_get_severity
+stc_config_error_get_message
+<SUBSECTION Private>
+stc_config_error_get_type
+STC_TYPE_CONFIG_ERROR
+stc_config_error_severity_get_type
+STC_TYPE_CONFIG_ERROR_SEVERITY
+</SECTION>
diff --git a/doc/stc.types b/doc/stc.types
index 15a8430..c15e6ed 100644
--- a/doc/stc.types
+++ b/doc/stc.types
@@ -1,3 +1,4 @@
stc_item_get_type
stc_monitor_get_type
stc_operation_get_type
+stc_config_error_get_type
diff --git a/stc/Makefile.am b/stc/Makefile.am
index 1ee3072..41addff 100644
--- a/stc/Makefile.am
+++ b/stc/Makefile.am
@@ -46,6 +46,7 @@ libstc_1includedir=$(includedir)/stc-1/stc
libstc_1include_HEADERS= \
stc.h \
+ stcconfigerror.h \
stcenums.h \
stcenumtypes.h \
stcerror.h \
@@ -57,6 +58,7 @@ libstc_1include_HEADERS= \
libstc_1_la_SOURCES = \
$(BUILT_SOURCES) \
stcenums.h \
+ stcconfigerror.h stcconfigerror.c \
stcerror.h stcerror.c \
stcitem.h stcitem.c \
stcmonitor.h stcmonitor.c \
diff --git a/stc/stc.c b/stc/stc.c
index 2d3b093..61ce14e 100644
--- a/stc/stc.c
+++ b/stc/stc.c
@@ -191,30 +191,57 @@ _color_run_pager (void)
/* ---------------------------------------------------------------------------------------------------- */
static void
-error_handler (StcMonitor *monitor,
- const gchar *filename,
- gint line_no,
- GError *error,
- gpointer user_data)
+print_config_error (StcMonitor *monitor,
+ StcConfigError *config_error)
{
GString *str;
+ const gchar *item_id;
+ const gchar *filename;
+ gint line_number;
+ StcConfigErrorSeverity severity;
+ const gchar *message;
+
+ item_id = stc_config_error_get_item_id (config_error);
+ filename = stc_config_error_get_filename (config_error);
+ line_number = stc_config_error_get_line_number (config_error);
+ severity = stc_config_error_get_severity (config_error);
+ message = stc_config_error_get_message (config_error);
str = g_string_new (NULL);
g_string_append_printf (str, "%s%s", _color_get (_COLOR_BOLD_ON), _color_get (_COLOR_FG_YELLOW));
if (filename != NULL)
{
- if (line_no >= 0)
- g_string_append_printf (str, "%s:%d: ", filename, line_no);
+ if (line_number >= 0)
+ g_string_append_printf (str, "%s:%d: ", filename, line_number);
else
g_string_append_printf (str, "%s: ", filename);
}
g_string_append_printf (str, "%s", _color_get (_COLOR_RESET));
- g_string_append_printf (str, "%s%s", _color_get (_COLOR_BOLD_ON), _color_get (_COLOR_FG_RED));
- g_string_append_printf (str, "%s", error->message);
- g_string_append_printf (str, "%s", _color_get (_COLOR_RESET));
- g_string_append_printf (str, "%s", _color_get (_COLOR_FG_BLUE));
- g_string_append_printf (str, " (%s, %d)", g_quark_to_string (error->domain), error->code);
- g_string_append_printf (str, "%s", _color_get (_COLOR_RESET));
+ if (item_id != NULL)
+ {
+ g_string_append_printf (str, "%s%s%s: %s",
+ _color_get (_COLOR_BOLD_ON),
+ _color_get (_COLOR_FG_BLUE),
+ item_id,
+ _color_get (_COLOR_RESET));
+ }
+ switch (severity)
+ {
+ case STC_CONFIG_ERROR_SEVERITY_WARNING:
+ g_string_append_printf (str, "%s%s[WARNING]: %s",
+ _color_get (_COLOR_BOLD_ON),
+ _color_get (_COLOR_FG_YELLOW),
+ _color_get (_COLOR_RESET));
+ break;
+
+ case STC_CONFIG_ERROR_SEVERITY_ERROR:
+ g_string_append_printf (str, "%s%s[ERROR]: %s",
+ _color_get (_COLOR_BOLD_ON),
+ _color_get (_COLOR_FG_RED),
+ _color_get (_COLOR_RESET));
+ break;
+ }
+ g_string_append_printf (str, "%s", message);
if (_color_stdin_is_tty)
g_print ("%s\n", str->str);
@@ -223,6 +250,22 @@ error_handler (StcMonitor *monitor,
g_string_free (str, TRUE);
}
+static void
+print_all_config_errors (StcMonitor *monitor)
+{
+ GList *config_errors;
+ GList *l;
+
+ config_errors = stc_monitor_get_config_errors (monitor);
+ for (l = config_errors; l != NULL; l = l->next)
+ {
+ StcConfigError *config_error = l->data;
+ print_config_error (monitor, config_error);
+ }
+ g_list_foreach (config_errors, (GFunc) stc_config_error_unref, NULL);
+ g_list_free (config_errors);
+}
+
/* ---------------------------------------------------------------------------------------------------- */
static const GOptionEntry command_list_entries[] =
@@ -274,7 +317,8 @@ handle_command_list (gint *argc,
_color_run_pager ();
- monitor = stc_monitor_new (error_handler, NULL);
+ monitor = stc_monitor_new ();
+ print_all_config_errors (monitor);
items = stc_monitor_get_items (monitor);
@@ -877,7 +921,8 @@ handle_command_start_stop (gint *argc,
g_print ("--allow-degraded \n");
}
- monitor = stc_monitor_new (error_handler, NULL);
+ monitor = stc_monitor_new ();
+ print_all_config_errors (monitor);
if (complete_ids)
{
diff --git a/stc/stc.h b/stc/stc.h
index fa606ab..1ce5b9a 100644
--- a/stc/stc.h
+++ b/stc/stc.h
@@ -34,6 +34,7 @@
#include <stc/stcerror.h>
#include <stc/stcitem.h>
#include <stc/stcmonitor.h>
+#include <stc/stcconfigerror.h>
#include <stc/stcoperation.h>
#undef __STC_INSIDE_STC_H__
diff --git a/stc/stcconfigerror.c b/stc/stcconfigerror.c
new file mode 100644
index 0000000..a1774b7
--- /dev/null
+++ b/stc/stcconfigerror.c
@@ -0,0 +1,229 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <zeuthen@gmail.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "stcconfigerror.h"
+
+/**
+ * SECTION:stcconfigerror
+ * @title: StcConfigError
+ * @short_description: Details about configuration file errors
+ *
+ * Boxed type used for reporting errors in configuration files.
+ */
+
+/**
+ * StcConfigError:
+ *
+ * The #StcConfigError structure contains only private data and should
+ * only be accessed using the provided API.
+ */
+struct _StcConfigError
+{
+ volatile gint ref_count;
+ gchar *item_id;
+ gchar *filename;
+ gint line_number;
+ StcConfigErrorSeverity severity;
+ gchar *message;
+};
+
+G_DEFINE_BOXED_TYPE (StcConfigError, stc_config_error, stc_config_error_ref, stc_config_error_unref);
+
+/**
+ * stc_config_error_ref:
+ * @error: A #StcConfigError.
+ *
+ * Increases the reference count on @error.
+ *
+ * Returns: The same @error.
+ */
+StcConfigError *
+stc_config_error_ref (StcConfigError *error)
+{
+ g_atomic_int_inc (&error->ref_count);
+ return error;
+}
+
+/**
+ * stc_config_error_unref:
+ * @error: A #StcConfigError.
+ *
+ * Decreases the reference count on @error. When the reference count
+ * drops to zero, all resources used are freed.
+ */
+void
+stc_config_error_unref (StcConfigError *error)
+{
+ if (g_atomic_int_dec_and_test (&error->ref_count))
+ {
+ g_free (error->item_id);
+ g_free (error->filename);
+ g_free (error->message);
+ g_slice_free (StcConfigError, error);
+ }
+}
+
+/**
+ * stc_config_error_new:
+ * @item_id: The item the error is about or %NULL if not about a specific item.
+ * @filename: The filename where the error is.
+ * @line_number: The line number where the error is or -1 if unknown.
+ * @severity: The severity of the error.
+ * @message: A human-readable message describing the error.
+ *
+ * Create a new #StcConfigError.
+ *
+ * Returns: A newly allocated #StcConfigError structure. Free with stc_config_error_unref().
+ */
+StcConfigError *
+stc_config_error_new (const gchar *item_id,
+ const gchar *filename,
+ gint line_number,
+ StcConfigErrorSeverity severity,
+ const gchar *message)
+{
+ StcConfigError *error;
+ error = g_slice_new0 (StcConfigError);
+ error->ref_count = 1;
+ error->item_id = g_strdup (item_id);
+ error->filename = g_strdup (filename);
+ error->line_number = line_number;
+ error->severity = severity;
+ error->message = g_strdup (message);
+ return error;
+}
+
+/**
+ * stc_config_error_get_item_id:
+ * @error: A #StcConfigError.
+ *
+ * Gets the item the error is for, if any.
+ *
+ * Returns: A string owned by @error or %NULL. Do not free.
+ */
+const gchar *
+stc_config_error_get_item_id (StcConfigError *error)
+{
+ return error->item_id;
+}
+
+/**
+ * stc_config_error_get_filename:
+ * @error: A #StcConfigError.
+ *
+ * Gets the filename where the error is.
+ *
+ * Returns: A string owned by @error. Do not free.
+ */
+const gchar *
+stc_config_error_get_filename (StcConfigError *error)
+{
+ return error->filename;
+}
+
+/**
+ * stc_config_error_get_line_number:
+ * @error: A #StcConfigError.
+ *
+ * Gets the line number where the error is.
+ *
+ * Returns: The line number or -1 if unknown.
+ */
+gint
+stc_config_error_get_line_number (StcConfigError *error)
+{
+ return error->line_number;
+}
+
+/**
+ * stc_config_error_get_severity:
+ * @error: A #StcConfigError.
+ *
+ * Gets the severity of the error.
+ *
+ * Returns: A value from the #StcConfigErrorSeverity enumeration.
+ */
+StcConfigErrorSeverity
+stc_config_error_get_severity (StcConfigError *error)
+{
+ return error->severity;
+}
+
+/**
+ * stc_config_error_get_message:
+ * @error: A #StcConfigError.
+ *
+ * Gets the human-readable message describing the error.
+ *
+ * Returns: A string owned by @error. Do not free.
+ */
+const gchar *
+stc_config_error_get_message (StcConfigError *error)
+{
+ return error->message;
+}
+
+/**
+ * stc_config_error_compare:
+ * @error: A #StcConfigError.
+ * @other_error: Another #StcConfigError.
+ *
+ * Compares @error and @other_error.
+ *
+ * Returns: Negative value if @error < @other_error; zero if @error = @other_error; positive value if @error > @other_error.
+ */
+gint
+stc_config_error_compare (StcConfigError *error,
+ StcConfigError *other_error)
+{
+ StcConfigError *a;
+ StcConfigError *b;
+ gint ret;
+
+ a = error;
+ b = other_error;
+
+ ret = g_strcmp0 (a->filename, b->filename);
+ if (ret != 0)
+ goto out;
+
+ ret = a->line_number - b->line_number;
+ if (ret != 0)
+ goto out;
+
+ ret = g_strcmp0 (a->item_id, b->item_id);
+ if (ret != 0)
+ goto out;
+
+ ret = a->severity - b->severity;
+ if (ret != 0)
+ goto out;
+
+ ret = g_strcmp0 (a->message, b->message);
+
+ out:
+ return ret;
+}
diff --git a/stc/stcconfigerror.h b/stc/stcconfigerror.h
new file mode 100644
index 0000000..4e56c1d
--- /dev/null
+++ b/stc/stcconfigerror.h
@@ -0,0 +1,60 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <zeuthen@gmail.com>
+ */
+
+
+#if !defined (__STC_INSIDE_STC_H__) && !defined (STC_COMPILATION)
+#error "Only <stc/stc.h> can be included directly."
+#endif
+
+#ifndef __STC_CONFIG_ERROR_H__
+#define __STC_CONFIG_ERROR_H__
+
+#include <stc/stctypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * STC_TYPE_CONFIG_ERROR:
+ *
+ * The #GType for a boxed type holding a #StcConfigError structure.
+ */
+#define STC_TYPE_CONFIG_ERROR (stc_config_error_get_type ())
+
+GType stc_config_error_get_type (void) G_GNUC_CONST;
+StcConfigError *stc_config_error_new (const gchar *item_id,
+ const gchar *filename,
+ gint line_number,
+ StcConfigErrorSeverity severity,
+ const gchar *message);
+StcConfigError *stc_config_error_ref (StcConfigError *error);
+void stc_config_error_unref (StcConfigError *error);
+gint stc_config_error_compare (StcConfigError *error,
+ StcConfigError *other_error);
+const gchar *stc_config_error_get_item_id (StcConfigError *error);
+const gchar *stc_config_error_get_filename (StcConfigError *error);
+gint stc_config_error_get_line_number (StcConfigError *error);
+StcConfigErrorSeverity stc_config_error_get_severity (StcConfigError *error);
+const gchar *stc_config_error_get_message (StcConfigError *error);
+
+G_END_DECLS
+
+#endif /* __STC_CONFIG_ERROR_H__ */
diff --git a/stc/stcd.c b/stc/stcd.c
index 28ad6a6..a0966f8 100644
--- a/stc/stcd.c
+++ b/stc/stcd.c
@@ -163,12 +163,6 @@ _StcDaemon *_stc_daemon_new (void);
static void maybe_act_on_item (_StcDaemon *daemon,
StcItem *item);
-static void error_handler (StcMonitor *monitor,
- const gchar *filename,
- gint line_no,
- GError *error,
- gpointer user_data);
-
static void on_item_added (StcMonitor *monitor,
StcItem *item,
gpointer user_data);
@@ -181,8 +175,13 @@ static void on_item_changed (StcMonitor *monitor,
StcItem *item,
gpointer user_data);
+static void on_config_reloaded (StcMonitor *monitor,
+ gpointer user_data);
+
static StcOperation * get_operation (_StcDaemon *daemon);
+static void print_all_config_errors (StcMonitor *monitor);
+
enum
{
PENDING_ITEMS_CHANGED_SIGNAL,
@@ -213,7 +212,9 @@ _stc_daemon_init (_StcDaemon *daemon)
daemon->pending_item_ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- daemon->monitor = stc_monitor_new (error_handler, NULL);
+ daemon->monitor = stc_monitor_new ();
+ print_all_config_errors (daemon->monitor);
+
g_signal_connect (daemon->monitor,
"item-added",
G_CALLBACK (on_item_added),
@@ -226,6 +227,10 @@ _stc_daemon_init (_StcDaemon *daemon)
"item-changed",
G_CALLBACK (on_item_changed),
daemon);
+ g_signal_connect (daemon->monitor,
+ "config-reloaded",
+ G_CALLBACK (on_config_reloaded),
+ daemon);
/* coldplug */
log_message (LOG_LEVEL_DEBUG, "coldplugging items");
@@ -449,27 +454,66 @@ _stc_daemon_start_serialized (_StcDaemon *daemon,
/* ---------------------------------------------------------------------------------------------------- */
static void
-error_handler (StcMonitor *monitor,
- const gchar *filename,
- gint line_no,
- GError *error,
- gpointer user_data)
+print_config_error (StcMonitor *monitor,
+ StcConfigError *config_error)
{
GString *str;
+ const gchar *item_id;
+ const gchar *filename;
+ gint line_number;
+ StcConfigErrorSeverity severity;
+ const gchar *message;
+ LogLevel level;
+
+ item_id = stc_config_error_get_item_id (config_error);
+ filename = stc_config_error_get_filename (config_error);
+ line_number = stc_config_error_get_line_number (config_error);
+ severity = stc_config_error_get_severity (config_error);
+ message = stc_config_error_get_message (config_error);
+
str = g_string_new (NULL);
if (filename != NULL)
{
- if (line_no >= 0)
- g_string_append_printf (str, "%s:%d: ", filename, line_no);
+ if (line_number >= 0)
+ g_string_append_printf (str, "%s:%d: ", filename, line_number);
else
g_string_append_printf (str, "%s: ", filename);
}
- g_string_append_printf (str, "%s", error->message);
- g_string_append_printf (str, " (%s, %d)", g_quark_to_string (error->domain), error->code);
- log_message (LOG_LEVEL_WARNING, "Error while parsing %s", str->str);
+ if (item_id != NULL)
+ {
+ g_string_append_printf (str, "%s: ", item_id);
+ }
+ switch (severity)
+ {
+ case STC_CONFIG_ERROR_SEVERITY_WARNING:
+ level = LOG_LEVEL_WARNING;
+ break;
+
+ case STC_CONFIG_ERROR_SEVERITY_ERROR:
+ level = LOG_LEVEL_ERROR;
+ break;
+ }
+ g_string_append_printf (str, "%s", message);
+ log_message (level, "%s", str->str);
g_string_free (str, TRUE);
}
+static void
+print_all_config_errors (StcMonitor *monitor)
+{
+ GList *config_errors;
+ GList *l;
+
+ config_errors = stc_monitor_get_config_errors (monitor);
+ for (l = config_errors; l != NULL; l = l->next)
+ {
+ StcConfigError *config_error = l->data;
+ print_config_error (monitor, config_error);
+ }
+ g_list_foreach (config_errors, (GFunc) stc_config_error_unref, NULL);
+ g_list_free (config_errors);
+}
+
/* ---------------------------------------------------------------------------------------------------- */
static void
@@ -826,6 +870,16 @@ on_item_changed (StcMonitor *monitor,
maybe_act_on_item (daemon, item);
}
+static void
+on_config_reloaded (StcMonitor *monitor,
+ gpointer user_data)
+{
+ _StcDaemon *daemon = _STC_DAEMON (user_data);
+
+ log_message (LOG_LEVEL_INFO, "Configuration reloaded");
+ print_all_config_errors (daemon->monitor);
+}
+
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
diff --git a/stc/stcenums.h b/stc/stcenums.h
index 5737310..b0ebd7e 100644
--- a/stc/stcenums.h
+++ b/stc/stcenums.h
@@ -98,6 +98,20 @@ typedef enum
STC_ITEM_STATE_DEFUNCT
} StcItemState;
+/**
+ * StcConfigErrorSeverity:
+ * @STC_CONFIG_ERROR_SEVERITY_WARNING: There is a problem but no configuration items was dropped.
+ * @STC_CONFIG_ERROR_SEVERITY_ERROR: There is a problem including dropping one or more configuration items.
+ *
+ * Severity level used in #StcConfigError.
+ */
+typedef enum
+{
+ STC_CONFIG_ERROR_SEVERITY_WARNING,
+ STC_CONFIG_ERROR_SEVERITY_ERROR
+} StcConfigErrorSeverity;
+
+
G_END_DECLS
#endif /* __STC_ENUMS_H__ */
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);
+ }
+}
+
diff --git a/stc/stcmonitor.h b/stc/stcmonitor.h
index 69be93e..0cdeff5 100644
--- a/stc/stcmonitor.h
+++ b/stc/stcmonitor.h
@@ -36,32 +36,12 @@ G_BEGIN_DECLS
#define STC_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), STC_TYPE_MONITOR, StcMonitor))
#define STC_IS_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), STC_TYPE_MONITOR))
-/**
- * StcErrorHandlerFunc:
- * @monitor: The #StcMonitor with the condition.
- * @filename: The path of the file that caused the error or %NULL.
- * @line_no: The line number the error occured at or -1 if unknown.
- * @error: The error.
- * @user_data: User data.
- *
- * Function pointer for a function that is called whenever @monitor encounters an error condition.
- *
- * This function is called from the
- * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
- * that @monitor was created in.
- */
-typedef void (*StcErrorHandlerFunc) (StcMonitor *monitor,
- const gchar *filename,
- gint line_no,
- GError *error,
- gpointer user_data);
-
GType stc_monitor_get_type (void) G_GNUC_CONST;
-StcMonitor *stc_monitor_new (StcErrorHandlerFunc error_handler_func,
- gpointer error_handler_user_data);
+StcMonitor *stc_monitor_new (void);
GList *stc_monitor_get_items (StcMonitor *monitor);
StcItem *stc_monitor_get_item_by_id (StcMonitor *monitor,
const gchar *item_id);
+GList *stc_monitor_get_config_errors (StcMonitor *monitor);
G_END_DECLS
diff --git a/stc/stctypes.h b/stc/stctypes.h
index 7756682..1f39de2 100644
--- a/stc/stctypes.h
+++ b/stc/stctypes.h
@@ -41,6 +41,9 @@ typedef struct _StcMonitor StcMonitor;
struct _StcOperation;
typedef struct _StcOperation StcOperation;
+struct _StcConfigError;
+typedef struct _StcConfigError StcConfigError;
+
G_END_DECLS
#endif /* __STC_TYPES_H__ */
diff --git a/stc/test.c b/stc/test.c
index 2652e76..c51c43c 100644
--- a/stc/test.c
+++ b/stc/test.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
+#include <locale.h>
#include <glib/gstdio.h>
@@ -118,32 +119,40 @@ static void item_append_str (StcItem *item,
/* ---------------------------------------------------------------------------------------------------- */
-static void
-on_error_append_str (StcMonitor *monitor,
- const gchar *filename,
- gint line_no,
- GError *error,
- gpointer user_data)
+static gchar *
+_stc_monitor_config_errors_to_string (StcMonitor *monitor)
{
- GString *str = user_data;
+ GList *errors;
+ GList *l;
+ GString *str;
- if (filename != NULL)
+ str = g_string_new (NULL);
+ errors = stc_monitor_get_config_errors (monitor);
+ for (l = errors; l != NULL; l = l->next)
{
- if (line_no >= 0)
- g_string_append_printf (str, "%s:%d: ", filename, line_no);
- else
- g_string_append_printf (str, "%s: ", filename);
+ StcConfigError *error = l->data;
+ g_string_append_printf (str,
+ "%s line=%d item_id=%s sev=%d: %s\n",
+ stc_config_error_get_filename (error),
+ stc_config_error_get_line_number (error),
+ stc_config_error_get_item_id (error) != NULL ? stc_config_error_get_item_id (error) : "-",
+ stc_config_error_get_severity (error),
+ stc_config_error_get_message (error));
}
+ g_list_foreach (errors, (GFunc) stc_config_error_unref, NULL);
+ g_list_free (errors);
- g_string_append_printf (str, "%s (%s, %d)\n", error->message, g_quark_to_string (error->domain), error->code);
+ return g_string_free (str, FALSE);
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
test_stc_basic (void)
{
StcMonitor *monitor;
- monitor = stc_monitor_new (NULL, NULL);
+ monitor = stc_monitor_new ();
g_object_unref (monitor);
}
@@ -151,19 +160,18 @@ static void
test_stc_no_conf (void)
{
StcMonitor *monitor;
- GString *str;
-
- str = g_string_new (NULL);
g_setenv ("STC_CONFIG_DIR", SRCDIR "/nonexistant", TRUE);
- monitor = stc_monitor_new (on_error_append_str, str);
+ monitor = stc_monitor_new ();
g_object_unref (monitor);
+#if 0 /* TODO */
g_assert_cmpstr (str->str, ==,
SRCDIR "/nonexistant/stc.conf.d: Error opening directory '" SRCDIR "/nonexistant/stc.conf.d': No such file or directory (g-file-error-quark, 4)\n"
SRCDIR "/nonexistant/stc.conf: No such file or directory (g-file-error-quark, 4)\n"
);
g_string_free (str, TRUE);
+#endif
}
static void
@@ -171,34 +179,35 @@ test_stc_semi_valid_conf (void)
{
StcMonitor *monitor;
GString *str;
- GString *str2;
GList *items;
GList *l;
+ gchar *s;
- str = g_string_new (NULL);
g_setenv ("STC_CONFIG_DIR", SRCDIR "/testdata/semi_valid_conf", TRUE);
- monitor = stc_monitor_new (on_error_append_str, str);
- g_assert_cmpstr (str->str, ==,
- SRCDIR "/testdata/semi_valid_conf/stc.conf: Error parsing key Auto for item BigStorage of type Filesystem: Key file contains key 'Auto' which has value that cannot be interpreted. (stc-error-quark, 1)\n"
- SRCDIR "/testdata/semi_valid_conf/stc.conf: Error parsing group name `Blah' (stc-error-quark, 1)\n"
- SRCDIR "/testdata/semi_valid_conf/stc.conf: Error parsing item type `XYZType' in group `XYZType ValidIdentifier' (stc-error-quark, 1)\n"
- SRCDIR "/testdata/semi_valid_conf/stc.conf: Invalid item identifer `with-dash' in group `Filesystem with-dash'. Only characters in [a-zA-Z0-9_] are supported. (stc-error-quark, 1)\n"
- SRCDIR "/testdata/semi_valid_conf/stc.conf: Error parsing group name `Filesystem with space' (stc-error-quark, 1)\n"
- SRCDIR "/testdata/semi_valid_conf/stc.conf: Raid item bar needs one of RaidUUID and RaidName options set. (stc-error-quark, 0)\n"
- SRCDIR "/testdata/semi_valid_conf/stc.conf.d/91.conf: Encountered item with duplicate id `multiple_instances_same_id'. Ignoring previous items. (stc-error-quark, 2)\n"
- SRCDIR "/testdata/semi_valid_conf/stc.conf: Item ItemWithUnresolved has unresolved dependency NonExisting. (stc-error-quark, 3)\n"
+ monitor = stc_monitor_new ();
+ s = _stc_monitor_config_errors_to_string (monitor);
+ g_assert_cmpstr (s, ==,
+ SRCDIR "/testdata/semi_valid_conf/stc.conf line=-1 item_id=- sev=1: Error parsing group name `Blah'. Expected two tokens, found 1\n"
+ SRCDIR "/testdata/semi_valid_conf/stc.conf line=-1 item_id=- sev=1: Error parsing group name `Filesystem with space'. Expected two tokens, found 3\n"
+ SRCDIR "/testdata/semi_valid_conf/stc.conf line=-1 item_id=- sev=1: Invalid item identifer with-dash in group `Filesystem with-dash'. Only characters in [a-zA-Z0-9_] are supported\n"
+ SRCDIR "/testdata/semi_valid_conf/stc.conf line=-1 item_id=- sev=1: Unrecognized item type XYZType in group `XYZType ValidIdentifier'\n"
+ SRCDIR "/testdata/semi_valid_conf/stc.conf line=-1 item_id=BigStorage sev=0: Error parsing key Auto: Key file contains key 'Auto' which has value that cannot be interpreted.\n"
+ SRCDIR "/testdata/semi_valid_conf/stc.conf line=-1 item_id=ItemWithUnresolved sev=0: Item has unresolved dependency on non-existing item NonExisting\n"
+ SRCDIR "/testdata/semi_valid_conf/stc.conf line=-1 item_id=bar sev=1: Raid item needs one of RaidUUID and RaidName options set\n"
+ SRCDIR "/testdata/semi_valid_conf/stc.conf.d/91.conf line=-1 item_id=multiple_instances_same_id sev=1: Encountered item with duplicate id. Ignoring previous item\n"
);
+ g_free (s);
- str2 = g_string_new (NULL);
+ str = g_string_new (NULL);
items = stc_monitor_get_items (monitor);
for (l = items; l != NULL; l = l->next)
{
StcItem *item = STC_ITEM (l->data);
- item_append_str (item, str2);
+ item_append_str (item, str);
}
g_list_foreach (items, (GFunc) g_object_unref, NULL);
g_list_free (items);
- g_assert_cmpstr (str2->str, ==,
+ g_assert_cmpstr (str->str, ==,
"id `in_pri_10'\n"
"comment `(none)'\n"
"type filesystem\n"
@@ -279,10 +288,9 @@ test_stc_semi_valid_conf (void)
"auto 1\n"
"\n"
);
- g_string_free (str2, TRUE);
+ g_string_free (str, TRUE);
g_object_unref (monitor);
- g_string_free (str, TRUE);
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -314,43 +322,43 @@ typedef enum
} _Event;
static void
-check_state (StcMonitor *monitor,
- StcItem *item,
- gint state,
- _Event event)
+check_state (StcMonitor *monitor,
+ StcItem *item,
+ gint state,
+ _Event event)
{
switch (state)
{
case 0:
- g_assert_cmpstr (stc_item_get_id (item), ==, "item1");
g_assert_cmpint (event, ==, _EVENT_ADDED);
+ g_assert_cmpstr (stc_item_get_id (item), ==, "item1");
break;
case 1:
- g_assert_cmpstr (stc_item_get_id (item), ==, "item2");
g_assert_cmpint (event, ==, _EVENT_ADDED);
+ g_assert_cmpstr (stc_item_get_id (item), ==, "item2");
g_assert_cmpstr (stc_item_get_option (item, "FilesystemDevice"), ==, "/dev/sdc");
break;
case 2:
- g_assert_cmpstr (stc_item_get_id (item), ==, "item1");
g_assert_cmpint (event, ==, _EVENT_REMOVED);
+ g_assert_cmpstr (stc_item_get_id (item), ==, "item1");
break;
case 3:
- g_assert_cmpstr (stc_item_get_id (item), ==, "item2");
g_assert_cmpint (event, ==, _EVENT_CHANGED);
+ g_assert_cmpstr (stc_item_get_id (item), ==, "item2");
g_assert_cmpstr (stc_item_get_option (item, "FilesystemDevice"), ==, "/dev/sda");
break;
case 4:
- g_assert_cmpstr (stc_item_get_id (item), ==, "item2");
g_assert_cmpint (event, ==, _EVENT_REMOVED);
+ g_assert_cmpstr (stc_item_get_id (item), ==, "item2");
break;
case 5:
- g_assert_cmpstr (stc_item_get_id (item), ==, "item3");
g_assert_cmpint (event, ==, _EVENT_ADDED);
+ g_assert_cmpstr (stc_item_get_id (item), ==, "item3");
break;
default:
@@ -412,7 +420,7 @@ test_stc_monitoring (void)
}
g_setenv ("STC_CONFIG_DIR", dirname, TRUE);
- monitor = stc_monitor_new (NULL, NULL);
+ monitor = stc_monitor_new ();
/* main timeout */
timeout_id = g_timeout_add_seconds (30, on_timeout, NULL);
@@ -527,6 +535,8 @@ main (int argc,
g_type_init ();
g_test_init (&argc, &argv, NULL);
+ setlocale (LC_ALL, "C");
+
loop = g_main_loop_new (NULL, FALSE);
g_test_add_func ("/stc/basic", test_stc_basic);