diff options
author | David Zeuthen <davidz@redhat.com> | 2010-09-29 17:34:15 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-09-29 17:34:15 -0400 |
commit | 69f0ce038868eda535aeaab3aaa6ab8d0e592fa0 (patch) | |
tree | 78ebcf5cb531512e4afea8d719193a51eb7600b1 | |
parent | 22a6d597597477eb14038b9d9b8a21b1b3c908d5 (diff) |
Updates
Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r-- | doc/stc-sections.txt | 2 | ||||
-rw-r--r-- | stc/Makefile.am | 8 | ||||
-rw-r--r-- | stc/stc.conf | 26 | ||||
-rw-r--r-- | stc/stcenums.h | 16 | ||||
-rw-r--r-- | stc/stcitem.c | 53 | ||||
-rw-r--r-- | stc/stcitem.h | 17 | ||||
-rw-r--r-- | stc/stcmarshal.list | 1 | ||||
-rw-r--r-- | stc/stcmonitor.c | 450 | ||||
-rw-r--r-- | stc/stcmonitor.h | 2 | ||||
-rw-r--r-- | stc/stcprivate.h | 43 | ||||
-rw-r--r-- | stc/test.c | 181 |
11 files changed, 765 insertions, 34 deletions
diff --git a/doc/stc-sections.txt b/doc/stc-sections.txt index cc1e510..49d81a8 100644 --- a/doc/stc-sections.txt +++ b/doc/stc-sections.txt @@ -4,6 +4,8 @@ StcMonitor stc_monitor_new stc_monitor_new_for_config_dir +stc_monitor_get_active +stc_monitor_activate stc_monitor_get_config_dir stc_monitor_get_items <SUBSECTION Standard> diff --git a/stc/Makefile.am b/stc/Makefile.am index 3ed139a..8442330 100644 --- a/stc/Makefile.am +++ b/stc/Makefile.am @@ -19,6 +19,12 @@ INCLUDES = \ $(GLIB_CFLAGS) \ $(NULL) +stcmarshal.h: stcmarshal.list + glib-genmarshal $< --prefix=_stc_marshal --header > $@ + +stcmarshal.c: stcmarshal.list + echo "#include \"stcmarshal.h\"" > $@ && glib-genmarshal $< --prefix=_stc_marshal --body >> $@ + stcenumtypes.h: stcenums.h stcenumtypes.h.template ( top_builddir=`cd $(top_builddir) && pwd`; \ cd $(srcdir) && glib-mkenums --template stcenumtypes.h.template stcenums.h ) > \ @@ -31,6 +37,7 @@ stcenumtypes.c: stcenums.h stcenumtypes.c.template BUILT_SOURCES = \ stcenumtypes.h stcenumtypes.c \ + stcmarshal.h stcmarshal.c \ $(NULL) lib_LTLIBRARIES=libstc-1.la @@ -52,6 +59,7 @@ libstc_1_la_SOURCES = \ stcerror.h stcerror.c \ stcitem.h stcitem.c \ stcmonitor.h stcmonitor.c \ + stcprivate.h \ $(NULL) libstc_1_la_CPPFLAGS = \ diff --git a/stc/stc.conf b/stc/stc.conf index 1ffec32..acfcd9b 100644 --- a/stc/stc.conf +++ b/stc/stc.conf @@ -1,6 +1,10 @@ +# check that we accept valid items... +# + [Filesystem BigStorage] NickName=BigStorage Device=/dev/disk/md-uuid-01234:56789 +Filesystem:mount_path=/mnt/BigStorage; Depends=BigStorage_mdraid Auto=yes @@ -11,10 +15,30 @@ UUID=01234:56789 [Filesystem SekritStuff] NickName=My Secret Stuff Device=/dev/disk/by-uuid/1234 -Options=Filesystem:options=noatime,dirsync +Options=Filesystem:mount_path=/mnt/SekritStuff;Filesystem:options=noatime,dirsync Depends=SekritStuff_LUKS [LUKS SekritStuff_LUKS] NickName=My Secret Stuff (Encrypted) Device=/dev/disk/by-uuid/12345 Options=LUKS:password=xyz123 + +# ...and that we reject invalid items +# + +# group name invalid (not two tokens) +[Blah] + +# unknown type +[XYZType ValidIdentifier] + +# invalid identifier (only [a-z][A-Z][0-9]_] allowed) +[Filesystem with-dash] + +# another invalid identifier +[Filesystem with space] + +# invalid options (no equal sign) +[MDRaid foo] +UUID=01234:56789 +Options=foo diff --git a/stc/stcenums.h b/stc/stcenums.h index 49065a2..d608561 100644 --- a/stc/stcenums.h +++ b/stc/stcenums.h @@ -33,27 +33,33 @@ G_BEGIN_DECLS /** * StcError: - * @STC_ERROR_FAILED: The operation failed. + * @STC_ERROR_FAILED: The operation failed / Generic error. + * @STC_ERROR_PARSE_ERROR: A configurtion is invalid. * * Error codes for the #STC_ERROR error domain and the * corresponding D-Bus error names. */ typedef enum { - STC_ERROR_FAILED + STC_ERROR_FAILED, + STC_ERROR_PARSE_ERROR } StcError; /** * StcItemType: * @STC_ITEM_TYPE_INVALID: Unknown or invalid item type. - * @STC_ITEM_TYPE_FSMOUNT: Filesystem mount. + * @STC_ITEM_TYPE_FILESYSTEM: Filesystem mount. + * @STC_ITEM_TYPE_MD_RAID: Linux Software RAID. + * @STC_ITEM_TYPE_LUKS: Linux Unified Key System. * - * Enumeration describing item types. + * Enumeration describing configuration item types. */ typedef enum { STC_ITEM_TYPE_INVALID, - STC_ITEM_TYPE_FSMOUNT + STC_ITEM_TYPE_FILESYSTEM, + STC_ITEM_TYPE_MD_RAID, + STC_ITEM_TYPE_LUKS } StcItemType; G_END_DECLS diff --git a/stc/stcitem.c b/stc/stcitem.c index fda895b..7490b0d 100644 --- a/stc/stcitem.c +++ b/stc/stcitem.c @@ -23,6 +23,7 @@ #include "config.h" #include "stcitem.h" +#include "stcprivate.h" /** * SECTION:stcitem @@ -47,8 +48,12 @@ struct _StcItem gchar *id; gchar *nick_name; gchar *target; + GHashTable *options; gboolean can_apply; gboolean applied; + + /* memoized */ + gchar **option_keys; }; typedef struct _StcItemClass StcItemClass; @@ -68,6 +73,8 @@ stc_item_finalize (GObject *object) g_free (item->id); g_free (item->nick_name); g_free (item->target); + g_hash_table_unref (item->options); + g_free (item->option_keys); if (G_OBJECT_CLASS (stc_item_parent_class)->finalize) G_OBJECT_CLASS (stc_item_parent_class)->finalize (object); @@ -146,17 +153,51 @@ stc_item_get_applied (StcItem *item) } -#if 0 StcItem * -_stc_item_new (dev_t dev, - const gchar *item_path) +_stc_item_new (StcItemType type, + const gchar *id, + const gchar *target, + const gchar *nick_name, + GHashTable *options) { StcItem *item; item = STC_ITEM (g_object_new (STC_TYPE_ITEM, NULL)); - item->dev = dev; - item->item_path = g_strdup (item_path); + + item->id = g_strdup (id); + item->target = g_strdup (target); + item->nick_name = g_strdup (nick_name); + item->type = type; + item->options = g_hash_table_ref (options); return item; } -#endif + +const gchar* const * +stc_item_get_option_keys (StcItem *item) +{ + g_return_val_if_fail (STC_IS_ITEM (item), NULL); + if (item->option_keys == NULL) + { + GHashTableIter iter; + const gchar *key; + GPtrArray *p; + + p = g_ptr_array_new (); + g_hash_table_iter_init (&iter, item->options); + while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL)) + g_ptr_array_add (p, (gpointer) key); + g_ptr_array_add (p, NULL); + item->option_keys = (gchar **) g_ptr_array_free (p, FALSE); + } + + return (const gchar *const *) item->option_keys; +} + +const gchar * +stc_item_get_option (StcItem *item, + const gchar *key) +{ + g_return_val_if_fail (STC_IS_ITEM (item), NULL); + return g_hash_table_lookup (item->options, key); +} diff --git a/stc/stcitem.h b/stc/stcitem.h index a666549..287bc65 100644 --- a/stc/stcitem.h +++ b/stc/stcitem.h @@ -37,13 +37,16 @@ G_BEGIN_DECLS #define STC_IS_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), STC_TYPE_ITEM)) GType stc_item_get_type (void) G_GNUC_CONST; -StcItemType stc_item_get_item_type (StcItem *item); -const gchar *stc_item_get_id (StcItem *item); -const gchar *stc_item_get_nick_name (StcItem *item); -const gchar *stc_item_get_target (StcItem *item); -GList *stc_item_get_dependencies (StcItem *item); -gboolean stc_item_get_can_apply (StcItem *item); -gboolean stc_item_get_applied (StcItem *item); +StcItemType stc_item_get_item_type (StcItem *item); +const gchar *stc_item_get_id (StcItem *item); +const gchar *stc_item_get_nick_name (StcItem *item); +const gchar *stc_item_get_target (StcItem *item); +const gchar* const *stc_item_get_option_keys (StcItem *item); +const gchar *stc_item_get_option (StcItem *item, + const gchar *key); +GList *stc_item_get_dependencies (StcItem *item); +gboolean stc_item_get_can_apply (StcItem *item); +gboolean stc_item_get_applied (StcItem *item); G_END_DECLS diff --git a/stc/stcmarshal.list b/stc/stcmarshal.list new file mode 100644 index 0000000..e0edfb9 --- /dev/null +++ b/stc/stcmarshal.list @@ -0,0 +1 @@ +VOID:STRING,INT,BOXED diff --git a/stc/stcmonitor.c b/stc/stcmonitor.c index dc1bc0f..f6d4242 100644 --- a/stc/stcmonitor.c +++ b/stc/stcmonitor.c @@ -22,7 +22,12 @@ #include "config.h" +#include <string.h> + +#include "stcerror.h" #include "stcmonitor.h" +#include "stcmarshal.h" +#include "stcprivate.h" /** * SECTION:stcmonitor @@ -43,8 +48,12 @@ struct _StcMonitor { GObject parent_instance; + GMainContext *context; + gchar *config_dir; + gboolean active; + GList *items; }; @@ -53,14 +62,45 @@ typedef struct _StcMonitorClass StcMonitorClass; struct _StcMonitorClass { GObjectClass parent_class; + + void (*error) (StcMonitor *monitor, + const gchar *filename, + gint line_no, + GError **error); }; enum { PROP_0, - PROP_CONFIG_DIR + PROP_CONFIG_DIR, + PROP_ACTIVE +}; + +enum +{ + ERROR_SIGNAL, + LAST_SIGNAL }; +static guint signals[LAST_SIGNAL] = { 0 }; + +static GList *stc_monitor_load_one_file (StcMonitor *monitor, + const gchar *path, + GError **error); + +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); + G_DEFINE_TYPE (StcMonitor, stc_monitor, G_TYPE_OBJECT); static void @@ -68,6 +108,8 @@ stc_monitor_finalize (GObject *object) { StcMonitor *monitor = STC_MONITOR (object); + if (monitor->context != NULL) + g_main_context_unref (monitor->context); g_free (monitor->config_dir); g_list_foreach (monitor->items, (GFunc) g_object_unref, NULL); g_list_free (monitor->items); @@ -90,6 +132,10 @@ stc_monitor_get_property (GObject *object, g_value_set_string (value, stc_monitor_get_config_dir (monitor)); break; + case PROP_ACTIVE: + g_value_set_boolean (value, stc_monitor_get_active (monitor)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -121,16 +167,9 @@ stc_monitor_set_property (GObject *object, static void stc_monitor_init (StcMonitor *monitor) { -} - - -static void -stc_monitor_constructed (GObject *object) -{ - //StcMonitor *monitor = STC_MONITOR (object); - - if (G_OBJECT_CLASS (stc_monitor_parent_class)->constructed) - G_OBJECT_CLASS (stc_monitor_parent_class)->constructed (object); + monitor->context = g_main_context_get_thread_default (); + if (monitor->context != NULL) + g_main_context_ref (monitor->context); } static void @@ -140,15 +179,13 @@ 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:config-dir: * - * The path for the configuration directory. If set to %NULL at - * construction time, then the <filename>/etc</filename> directory is used. + * The path for the configuration directory. */ g_object_class_install_property (gobject_class, PROP_CONFIG_DIR, @@ -160,8 +197,61 @@ stc_monitor_class_init (StcMonitorClass *klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * StcMonitor:active: + * + * Whether the monitor is currently active. + */ + g_object_class_install_property (gobject_class, + PROP_ACTIVE, + g_param_spec_boolean ("active", + "Active", + "Whether the monitor is currently active", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * StcMonitor::error: + * @monitor: The #StcMonitor emitting the signal + * @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. + * + * Emitted whenever a recoverable error (typically file parsing) is + * encountered. + * + * This signal is emitted in the + * <link linkend="g-main-context-push-thread-default">thread-default main loop</link> + * that @monitor was created in. + */ + signals[ERROR_SIGNAL] = g_signal_new ("error", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (StcMonitorClass, error), + NULL, + NULL, + _stc_marshal_VOID__STRING_INT_BOXED, + G_TYPE_NONE, + 3, + G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_ERROR); } +/** + * stc_monitor_new: + * + * Creates a new #StcMonitor that reads configuration files from the + * default configuration directory + * (e.g. <filename>/etc</filename>). + * + * The returned monitor isn't active. Use stc_monitor_activate() to load + * and monitor items. + * + * Returns: A #StcMonitor. Free with g_object_unref(). + */ StcMonitor * stc_monitor_new (void) { @@ -170,6 +260,17 @@ stc_monitor_new (void) return monitor; } +/** + * stc_monitor_new_for_config_dir: + * @config_dir: A path to where the <filename>stc.conf</filename> is stored. + * + * Creates a new #StcMonitor. + * + * The returned monitor isn't active. Use stc_monitor_activate() to load + * and monitor items. + * + * Returns: A #StcMonitor. Free with g_object_unref(). + */ StcMonitor * stc_monitor_new_for_config_dir (const gchar *config_dir) { @@ -183,6 +284,63 @@ stc_monitor_new_for_config_dir (const gchar *config_dir) return monitor; } +/** + * stc_monitor_activate: + * @monitor: A #StcMonitor that isn't active. + * + * Starts @monitor. If you are interested in reporting errors, connect + * to the #StcMonitor::error signal prior to invoking this method. + */ +void +stc_monitor_activate (StcMonitor *monitor) +{ + gchar *path; + GError *error; + + g_return_if_fail (STC_IS_MONITOR (monitor)); + g_return_if_fail (!monitor->active); + + path = g_strdup_printf ("%s/stc.conf", monitor->config_dir); + error = NULL; + monitor->items = stc_monitor_load_one_file (monitor, path, &error); + if (error != NULL) + { + stc_monitor_emit_gerror (monitor, + path, + -1, + error); + g_error_free (error); + } + g_free (path); + + monitor->active = TRUE; + g_object_notify (G_OBJECT (monitor), "active"); +} + + +/** + * stc_monitor_get_active: + * @monitor: A #StcMonitor. + * + * Gets whether @monitor is active. + * + * Returns: %TRUE if monitor is active, %FALSE otherwise. + */ +gboolean +stc_monitor_get_active (StcMonitor *monitor) +{ + g_return_val_if_fail (STC_IS_MONITOR (monitor), FALSE); + return monitor->active; +} + +/** + * stc_monitor_get_config_dir: + * @monitor: A #StcMonitor. + * + * Gets the configuration directory used by @monitor. + * + * Returns: A directory name. Do not free, the string is owned by @monitor. + */ const gchar * stc_monitor_get_config_dir (StcMonitor *monitor) { @@ -190,9 +348,271 @@ stc_monitor_get_config_dir (StcMonitor *monitor) return monitor->config_dir; } +/** + * stc_monitor_get_items: + * @monitor: An active #StcMonitor. + * + * Gets the configuration items detected by @monitor. + * + * Returns: A list of configuration items. The returned list must be + * with g_list_free() after each element has been unreffed using + * g_object_unref(). + */ GList * stc_monitor_get_items (StcMonitor *monitor) { - return NULL; + GList *ret; + + g_return_val_if_fail (STC_IS_MONITOR (monitor), NULL); + g_return_val_if_fail (monitor->active, NULL); + + ret = g_list_copy (monitor->items); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + + return ret; } +static StcItemType +item_type_from_string (const gchar *str) +{ + StcItemType ret; + + g_return_val_if_fail (str != NULL, STC_ITEM_TYPE_INVALID); + + ret = STC_ITEM_TYPE_INVALID; + if (g_strcmp0 (str, "Filesystem") == 0) + ret = STC_ITEM_TYPE_FILESYSTEM; + else if (g_strcmp0 (str, "MDRaid") == 0) + ret = STC_ITEM_TYPE_MD_RAID; + else if (g_strcmp0 (str, "LUKS") == 0) + ret = STC_ITEM_TYPE_LUKS; + + return ret; +} + +static gboolean +is_valid_item_id (const gchar *str) +{ + guint n; + gboolean ret; + + g_return_val_if_fail (str != NULL, FALSE); + + ret = FALSE; + + for (n = 0; str[n] != '\0'; n++) + { + gint c = str[n]; + if (!(g_ascii_isalnum (c) || c == '_')) + goto out; + } + + ret = TRUE; + + out: + return ret; +} + +static GList * +stc_monitor_load_one_file (StcMonitor *monitor, + const gchar *path, + GError **error) +{ + GList *ret; + GKeyFile *key_file; + gchar **groups; + guint n; + gboolean failed; + + 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; + + groups = g_key_file_get_groups (key_file, NULL); + for (n = 0; groups != NULL && groups[n] != NULL; n++) + { + const gchar *group = groups[n]; + gchar **tokens; + StcItemType item_type; + const gchar *item_id; + gchar *target; + gchar *nick_name; + gchar *s; + gchar **options_strv; + StcItem *item; + GHashTable *options; + + tokens = NULL; + target = NULL; + nick_name = NULL; + options = NULL; + + 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); + 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); + goto process_next_item; + } + + 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); + goto process_next_item; + } + + /* resolve target (TODO: bail if more than one of the allowed keys are present) */ + if ((s = g_key_file_get_string (key_file, group, "Device", NULL)) != NULL) + { + target = g_strdup_printf ("Device=%s", s); + g_free (s); + } + else if ((s = g_key_file_get_string (key_file, group, "UUID", NULL)) != NULL) + { + target = g_strdup_printf ("UUID=%s", s); + g_free (s); + } + else if ((s = g_key_file_get_string (key_file, group, "Label", NULL)) != NULL) + { + target = g_strdup_printf ("Label=%s", s); + g_free (s); + } + else + { + stc_monitor_emit_stc_error (monitor, + path, + -1, + STC_ERROR_PARSE_ERROR, + "No target key (supported: Device, UUID, Label) keys found " + "in item %s of type %s.", + item_id, + tokens[0]); + goto process_next_item; + } + + /* Options is optional */ + options_strv = g_key_file_get_string_list (key_file, group, "Options", NULL, NULL); + options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + if (options_strv != NULL) + { + guint m; + for (m = 0; options_strv[m] != NULL; m++) + { + s = strstr (options_strv[m], "="); + if (s == NULL) + { + stc_monitor_emit_stc_error (monitor, + path, + -1, + STC_ERROR_PARSE_ERROR, + "Element %d of Options, `%s', for item %s of type %s is malformed " + "(no equal sign found).", + m, + options_strv[m], + item_id, + tokens[0]); + g_strfreev (options_strv); + goto process_next_item; + } + g_hash_table_insert (options, + g_strndup (options_strv[m], s - options_strv[m]), + g_strdup (s + 1)); + } + g_strfreev (options_strv); + } + + /* NickName is optional */ + nick_name = g_key_file_get_string (key_file, group, "NickName", NULL); + + item = _stc_item_new (item_type, item_id, target, nick_name, options); + ret = g_list_prepend (ret, item); + + process_next_item: + g_strfreev (tokens); + g_free (target); + g_free (nick_name); + if (options != NULL) + g_hash_table_unref (options); + } + + failed = FALSE; + + out: + if (failed) + { + g_list_foreach (ret, (GFunc) g_object_unref, NULL); + g_list_free (ret); + ret = NULL; + } + else + { + ret = g_list_reverse (ret); + } + g_key_file_free (key_file); + g_strfreev (groups); + return ret; +} + +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); + g_signal_emit (monitor, signals[ERROR_SIGNAL], 0, filename, line_no, error); +} + +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); +} diff --git a/stc/stcmonitor.h b/stc/stcmonitor.h index 4cf2e3c..a4ee942 100644 --- a/stc/stcmonitor.h +++ b/stc/stcmonitor.h @@ -39,6 +39,8 @@ G_BEGIN_DECLS GType stc_monitor_get_type (void) G_GNUC_CONST; StcMonitor *stc_monitor_new (void); StcMonitor *stc_monitor_new_for_config_dir (const gchar *config_dir); +void stc_monitor_activate (StcMonitor *monitor); +gboolean stc_monitor_get_active (StcMonitor *monitor); const gchar *stc_monitor_get_config_dir (StcMonitor *monitor); GList *stc_monitor_get_items (StcMonitor *monitor); diff --git a/stc/stcprivate.h b/stc/stcprivate.h new file mode 100644 index 0000000..f7325cb --- /dev/null +++ b/stc/stcprivate.h @@ -0,0 +1,43 @@ +/* -*- 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_COMPILATION) +#error "stcprivate.h is a private header file." +#endif + +#ifndef __STC_PRIVATE_H__ +#define __STC_PRIVATE_H__ + +#include <stc/stctypes.h> + +G_BEGIN_DECLS + +StcItem *_stc_item_new (StcItemType type, + const gchar *id, + const gchar *target, + const gchar *nick_name, + GHashTable *options); + +G_END_DECLS + +#endif /* __STC_PRIVATE_H__ */ @@ -24,6 +24,92 @@ /* ---------------------------------------------------------------------------------------------------- */ +static const gchar * +item_type_to_str (StcItemType type) +{ + GEnumClass *klass; + GEnumValue *value; + const gchar *ret; + + ret = "<Unregistered enum type>"; + klass = g_type_class_ref (STC_TYPE_ITEM_TYPE); + if (klass == NULL) + goto out; + + ret = "<Invalid enum value>"; + value = g_enum_get_value (klass, type); + if (value == NULL) + goto out; + + ret = value->value_nick; + + out: + if (klass != NULL) + g_type_class_unref (klass); + return ret; +} + +static void item_append_str (StcItem *item, + GString *str) +{ + const gchar* const *keys; + + keys = stc_item_get_option_keys (item); + + g_string_append_printf (str, + "id `%s'\n" + "target `%s'\n" + "nick-name `%s'\n" + "type %s\n" + "options ", + stc_item_get_id (item) != NULL ? stc_item_get_id (item) : "(none)", + stc_item_get_target (item) != NULL ? stc_item_get_target (item) : "(none)", + stc_item_get_nick_name (item) != NULL ? stc_item_get_nick_name (item) : "(none)", + item_type_to_str (stc_item_get_item_type (item))); + + if (g_strv_length ((gchar **) keys) == 0) + { + g_string_append (str, "(none)"); + } + else + { + guint n; + for (n = 0; keys[n] != NULL; n++) + { + const gchar *value; + if (n > 0) + g_string_append (str, "\n "); + value = stc_item_get_option (item, keys[n]); + g_string_append_printf (str, "%s -> `%s'", keys[n], value); + } + } + g_string_append (str, "\n"); + + g_string_append (str, "\n"); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_error_append_str (StcMonitor *monitor, + const gchar *filename, + gint line_no, + GError *error, + gpointer user_data) +{ + GString *str = user_data; + + if (filename != NULL) + { + if (line_no >= 0) + g_string_append_printf (str, "%s:%d: ", filename, line_no); + else + g_string_append_printf (str, "%s: ", filename); + } + + g_string_append_printf (str, "%s (%s, %d)\n", error->message, g_quark_to_string (error->domain), error->code); +} + static void test_stc_basic (void) { @@ -31,11 +117,104 @@ test_stc_basic (void) monitor = stc_monitor_new (); g_assert_cmpstr (stc_monitor_get_config_dir (monitor), ==, PACKAGE_SYSCONF_DIR); + g_assert (!stc_monitor_get_active (monitor)); + stc_monitor_activate (monitor); + g_assert (stc_monitor_get_active (monitor)); + g_object_unref (monitor); + + monitor = stc_monitor_new_for_config_dir (SRCDIR); + g_assert_cmpstr (stc_monitor_get_config_dir (monitor), ==, SRCDIR); + g_assert (!stc_monitor_get_active (monitor)); + stc_monitor_activate (monitor); + g_assert (stc_monitor_get_active (monitor)); + g_object_unref (monitor); +} + +static void +test_stc_no_conf (void) +{ + StcMonitor *monitor; + GString *str; + + str = g_string_new (NULL); + monitor = stc_monitor_new_for_config_dir (SRCDIR "/nonexistant"); + g_assert_cmpstr (stc_monitor_get_config_dir (monitor), ==, SRCDIR "/nonexistant"); + g_assert (!stc_monitor_get_active (monitor)); + g_signal_connect (monitor, + "error", + G_CALLBACK (on_error_append_str), + str); + stc_monitor_activate (monitor); + g_assert (stc_monitor_get_active (monitor)); g_object_unref (monitor); + g_assert_cmpstr (str->str, ==, + SRCDIR "/nonexistant/stc.conf: No such file or directory (g-file-error-quark, 4)\n"); + g_string_free (str, TRUE); +} +static void +test_stc_semi_valid_conf (void) +{ + StcMonitor *monitor; + GString *str; + GString *str2; + GList *items; + GList *l; + + str = g_string_new (NULL); monitor = stc_monitor_new_for_config_dir (SRCDIR); g_assert_cmpstr (stc_monitor_get_config_dir (monitor), ==, SRCDIR); + g_assert (!stc_monitor_get_active (monitor)); + g_signal_connect (monitor, + "error", + G_CALLBACK (on_error_append_str), + str); + stc_monitor_activate (monitor); + g_assert (stc_monitor_get_active (monitor)); + g_assert_cmpstr (str->str, ==, + SRCDIR "/stc.conf: Error parsing group name `Blah' (stc-error-quark, 1)\n" + SRCDIR "/stc.conf: Error parsing item type `XYZType' in group `XYZType ValidIdentifier' (stc-error-quark, 1)\n" + SRCDIR "/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 "/stc.conf: Error parsing group name `Filesystem with space' (stc-error-quark, 1)\n" + SRCDIR "/stc.conf: Element 0 of Options, `foo', for item foo of type MDRaid is malformed (no equal sign found). (stc-error-quark, 1)\n" + ); + str2 = 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); + } + g_assert_cmpstr (str2->str, ==, + "id `BigStorage'\n" + "target `Device=/dev/disk/md-uuid-01234:56789'\n" + "nick-name `BigStorage'\n" + "type filesystem\n" + "options (none)\n" + "\n" + "id `BigStorage_mdraid'\n" + "target `UUID=01234:56789'\n" + "nick-name `BigStorage RAID Array'\n" + "type md-raid\n" + "options (none)\n" + "\n" + "id `SekritStuff'\n" + "target `Device=/dev/disk/by-uuid/1234'\n" + "nick-name `My Secret Stuff'\n" + "type filesystem\n" + "options Filesystem:mount_path -> `/mnt/SekritStuff'\n" + " Filesystem:options -> `noatime,dirsync'\n" + "\n" + "id `SekritStuff_LUKS'\n" + "target `Device=/dev/disk/by-uuid/12345'\n" + "nick-name `My Secret Stuff (Encrypted)'\n" + "type luks\n" + "options LUKS:password -> `xyz123'\n" + "\n"); + g_string_free (str2, TRUE); + g_object_unref (monitor); + g_string_free (str, TRUE); } /* ---------------------------------------------------------------------------------------------------- */ @@ -50,6 +229,8 @@ main (int argc, g_test_init (&argc, &argv, NULL); g_test_add_func ("/stc/basic", test_stc_basic); + g_test_add_func ("/stc/no_conf", test_stc_no_conf); + g_test_add_func ("/stc/semi_valid_conf", test_stc_semi_valid_conf); ret = g_test_run(); |