]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - common/configuration.c
Show source of configuration keys
[sojka/lightdm.git] / common / configuration.c
1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  * 
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11
12 #include <string.h>
13
14 #include "configuration.h"
15
16 struct ConfigurationPrivate
17 {
18     gchar *dir;
19     GKeyFile *key_file;
20     GList *sources;
21     GHashTable *key_sources;
22 };
23
24 G_DEFINE_TYPE (Configuration, config, G_TYPE_OBJECT);
25
26 static Configuration *configuration_instance = NULL;
27
28 Configuration *
29 config_get_instance (void)
30 {
31     if (!configuration_instance)
32         configuration_instance = g_object_new (CONFIGURATION_TYPE, NULL);
33     return configuration_instance;
34 }
35
36 gboolean
37 config_load_from_file (Configuration *config, const gchar *path, GError **error)
38 {
39     GKeyFile *key_file;
40     gchar *source_path, **groups;
41     int i;
42
43     source_path = g_strdup (path);
44     config->priv->sources = g_list_append (config->priv->sources, source_path);
45
46     key_file = g_key_file_new ();
47     if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, error))
48     {
49         g_key_file_free (key_file);
50         return FALSE;
51     }
52
53     groups = g_key_file_get_groups (key_file, NULL);
54     for (i = 0; groups[i]; i++)
55     {
56         gchar **keys;
57         int j;
58
59         keys = g_key_file_get_keys (key_file, groups[i], NULL, error);
60         if (!keys)
61             break;
62
63         for (j = 0; keys[j]; j++)
64         {
65             gchar *value, *k;
66
67             value = g_key_file_get_value (key_file, groups[i], keys[j], NULL);
68             g_key_file_set_value (config->priv->key_file, groups[i], keys[j], value);
69             g_free (value);
70
71             k = g_strdup_printf ("%s]%s", groups[i], keys[j]);
72             g_hash_table_insert (config->priv->key_sources, k, source_path);
73         }
74
75         g_strfreev (keys);
76     }
77     g_strfreev (groups);
78
79     g_key_file_free (key_file);
80
81     return TRUE;
82 }
83
84 static gchar *
85 path_make_absolute (gchar *path)
86 {
87     gchar *cwd, *abs_path;
88
89     if (!path)
90         return NULL;
91
92     if (g_path_is_absolute (path))
93         return path;
94
95     cwd = g_get_current_dir ();
96     abs_path = g_build_filename (cwd, path, NULL);
97     g_free (path);
98
99     return abs_path;
100 }
101
102 static int
103 compare_strings (gconstpointer a, gconstpointer b)
104 {
105     return strcmp (a, b);
106 }
107
108 static void
109 load_config_directory (const gchar *path, GList **messages)
110 {
111     GDir *dir;
112     GList *files = NULL, *link;
113     GError *error = NULL;
114
115     /* Find configuration files */
116     dir = g_dir_open (path, 0, &error);
117     if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
118         g_printerr ("Failed to open configuration directory %s: %s\n", path, error->message);
119     g_clear_error (&error);
120     if (dir)
121     {
122         const gchar *name;
123         while ((name = g_dir_read_name (dir)))
124             files = g_list_append (files, g_strdup (name));
125         g_dir_close (dir);
126     }
127
128     /* Sort alphabetically and load onto existing configuration */
129     files = g_list_sort (files, compare_strings);
130     for (link = files; link; link = link->next)
131     {
132         gchar *filename = link->data;
133         gchar *conf_path;
134
135         conf_path = g_build_filename (path, filename, NULL);
136         if (g_str_has_suffix (filename, ".conf"))
137         {
138             if (messages)
139                 *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration from %s", conf_path));
140             config_load_from_file (config_get_instance (), conf_path, &error);
141             if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
142                 g_printerr ("Failed to load configuration from %s: %s\n", filename, error->message);
143             g_clear_error (&error);
144         }
145         else
146             g_debug ("Ignoring configuration file %s, it does not have .conf suffix", conf_path);
147         g_free (conf_path);
148     }
149     g_list_free_full (files, g_free);
150 }
151
152 static void
153 load_config_directories (const gchar * const *dirs, GList **messages)
154 {
155     gint i;
156
157     /* Load in reverse order, because XDG_* fields are preference-ordered and the directories in front should override directories in back. */
158     for (i = g_strv_length ((gchar **)dirs) - 1; i >= 0; i--)
159     {
160         gchar *full_dir = g_build_filename (dirs[i], "lightdm", "lightdm.conf.d", NULL);
161         if (messages)
162             *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration dirs from %s", full_dir));
163         load_config_directory (full_dir, messages);
164         g_free (full_dir);
165     }
166 }
167
168 gboolean
169 config_load_from_standard_locations (Configuration *config, const gchar *config_path, GList **messages)
170 {
171     gchar *config_d_dir = NULL;
172     gboolean explicit_config = FALSE;
173     gboolean success = TRUE;
174     GError *error = NULL;
175
176     load_config_directories (g_get_system_data_dirs (), messages);
177     load_config_directories (g_get_system_config_dirs (), messages);
178
179     if (config_path)
180     {
181         config->priv->dir = path_make_absolute (g_path_get_basename (config_path));
182         explicit_config = TRUE;
183     }
184     else
185     {
186         config->priv->dir = g_strdup (CONFIG_DIR);
187         config_d_dir = g_build_filename (config->priv->dir, "lightdm.conf.d", NULL);
188         config_path = g_build_filename (config->priv->dir, "lightdm.conf", NULL);
189     }
190
191     if (config_d_dir)
192         load_config_directory (config_d_dir, messages);
193     g_free (config_d_dir);
194
195     if (messages)
196         *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration from %s", config_path));
197     if (!config_load_from_file (config, config_path, &error))
198     {
199         gboolean is_empty;
200
201         is_empty = error && g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
202
203         if (explicit_config || !is_empty)
204         {
205             if (error)
206                 g_printerr ("Failed to load configuration from %s: %s\n", config_path, error->message);
207             success = FALSE;
208         }
209     }
210     g_clear_error (&error);
211
212     return success;
213 }
214
215 const gchar *
216 config_get_directory (Configuration *config)
217 {
218     return config->priv->dir;
219 }
220
221 gchar **
222 config_get_groups (Configuration *config)
223 {
224     return g_key_file_get_groups (config->priv->key_file, NULL);
225 }
226
227 gchar **
228 config_get_keys (Configuration *config, const gchar *group_name)
229 {
230     return g_key_file_get_keys (config->priv->key_file, group_name, NULL, NULL);
231 }
232
233 gboolean
234 config_has_key (Configuration *config, const gchar *section, const gchar *key)
235 {
236     return g_key_file_has_key (config->priv->key_file, section, key, NULL);
237 }
238
239 GList *
240 config_get_sources (Configuration *config)
241 {
242     return config->priv->sources;
243 }
244
245 const gchar *
246 config_get_source (Configuration *config, const gchar *section, const gchar *key)
247 {
248     gchar *k;
249     const gchar *source;
250
251     k = g_strdup_printf ("%s]%s", section, key);
252     source = g_hash_table_lookup (config->priv->key_sources, k);
253     g_free (k);
254
255     return source;
256 }
257
258 void
259 config_set_string (Configuration *config, const gchar *section, const gchar *key, const gchar *value)
260 {
261     g_key_file_set_string (config->priv->key_file, section, key, value);
262 }
263
264 gchar *
265 config_get_string (Configuration *config, const gchar *section, const gchar *key)
266 {
267     return g_key_file_get_string (config->priv->key_file, section, key, NULL);
268 }
269
270 void
271 config_set_string_list (Configuration *config, const gchar *section, const gchar *key, const gchar **value, gsize length)
272 {
273     g_key_file_set_string_list (config->priv->key_file, section, key, value, length);
274 }
275
276 gchar **
277 config_get_string_list (Configuration *config, const gchar *section, const gchar *key)
278 {
279     return g_key_file_get_string_list (config->priv->key_file, section, key, NULL, NULL);
280 }
281
282 void
283 config_set_integer (Configuration *config, const gchar *section, const gchar *key, gint value)
284 {
285     g_key_file_set_integer (config->priv->key_file, section, key, value);
286 }
287
288 gint
289 config_get_integer (Configuration *config, const gchar *section, const gchar *key)
290 {
291     return g_key_file_get_integer (config->priv->key_file, section, key, NULL);
292 }
293
294 void
295 config_set_boolean (Configuration *config, const gchar *section, const gchar *key, gboolean value)
296 {
297     g_key_file_set_boolean (config->priv->key_file, section, key, value);
298 }
299
300 gboolean
301 config_get_boolean (Configuration *config, const gchar *section, const gchar *key)
302 {
303     return g_key_file_get_boolean (config->priv->key_file, section, key, NULL);
304 }
305
306 static void
307 config_init (Configuration *config)
308 {
309     config->priv = G_TYPE_INSTANCE_GET_PRIVATE (config, CONFIGURATION_TYPE, ConfigurationPrivate);
310     config->priv->key_file = g_key_file_new ();
311     config->priv->key_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
312 }
313
314 static void
315 config_finalize (GObject *object)
316 {
317     Configuration *self;
318
319     self = CONFIGURATION (object);
320
321     g_free (self->priv->dir);
322     g_key_file_free (self->priv->key_file);
323     g_list_free_full (self->priv->sources, g_free);
324     g_hash_table_destroy (self->priv->key_sources);
325
326     G_OBJECT_CLASS (config_parent_class)->finalize (object);  
327 }
328
329 static void
330 config_class_init (ConfigurationClass *klass)
331 {
332     GObjectClass *object_class = G_OBJECT_CLASS (klass);
333
334     object_class->finalize = config_finalize;  
335
336     g_type_class_add_private (klass, sizeof (ConfigurationPrivate));
337 }