]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - common/configuration.c
Merged changes from parent branch
[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     key_file = g_key_file_new ();
44     if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, error))
45     {
46         g_key_file_free (key_file);
47         return FALSE;
48     }
49
50     source_path = g_strdup (path);
51     config->priv->sources = g_list_append (config->priv->sources, source_path);
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, *path;
172     gboolean success = TRUE;
173     GError *error = NULL;
174
175     g_return_val_if_fail (config->priv->dir == NULL, FALSE);
176
177     load_config_directories (g_get_system_data_dirs (), messages);
178     load_config_directories (g_get_system_config_dirs (), messages);
179
180     if (config_path)
181     {
182         path = g_strdup (config_path);
183         config->priv->dir = path_make_absolute (g_path_get_basename (config_path));
184     }
185     else
186     {
187         config->priv->dir = g_strdup (CONFIG_DIR);
188         config_d_dir = g_build_filename (config->priv->dir, "lightdm.conf.d", NULL);
189         path = g_build_filename (config->priv->dir, "lightdm.conf", NULL);
190     }
191
192     if (config_d_dir)
193         load_config_directory (config_d_dir, messages);
194
195     if (messages)
196         *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration from %s", path));
197     if (!config_load_from_file (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 (config_path || !is_empty)
204         {
205             if (error)
206                 g_printerr ("Failed to load configuration from %s: %s\n", path, error->message);
207             success = FALSE;
208         }
209     }
210     g_clear_error (&error);
211
212     g_free (config_d_dir);
213     g_free (path);
214
215     return success;
216 }
217
218 const gchar *
219 config_get_directory (Configuration *config)
220 {
221     return config->priv->dir;
222 }
223
224 gchar **
225 config_get_groups (Configuration *config)
226 {
227     return g_key_file_get_groups (config->priv->key_file, NULL);
228 }
229
230 gchar **
231 config_get_keys (Configuration *config, const gchar *group_name)
232 {
233     return g_key_file_get_keys (config->priv->key_file, group_name, NULL, NULL);
234 }
235
236 gboolean
237 config_has_key (Configuration *config, const gchar *section, const gchar *key)
238 {
239     return g_key_file_has_key (config->priv->key_file, section, key, NULL);
240 }
241
242 GList *
243 config_get_sources (Configuration *config)
244 {
245     return config->priv->sources;
246 }
247
248 const gchar *
249 config_get_source (Configuration *config, const gchar *section, const gchar *key)
250 {
251     gchar *k;
252     const gchar *source;
253
254     k = g_strdup_printf ("%s]%s", section, key);
255     source = g_hash_table_lookup (config->priv->key_sources, k);
256     g_free (k);
257
258     return source;
259 }
260
261 void
262 config_set_string (Configuration *config, const gchar *section, const gchar *key, const gchar *value)
263 {
264     g_key_file_set_string (config->priv->key_file, section, key, value);
265 }
266
267 gchar *
268 config_get_string (Configuration *config, const gchar *section, const gchar *key)
269 {
270     return g_key_file_get_string (config->priv->key_file, section, key, NULL);
271 }
272
273 void
274 config_set_string_list (Configuration *config, const gchar *section, const gchar *key, const gchar **value, gsize length)
275 {
276     g_key_file_set_string_list (config->priv->key_file, section, key, value, length);
277 }
278
279 gchar **
280 config_get_string_list (Configuration *config, const gchar *section, const gchar *key)
281 {
282     return g_key_file_get_string_list (config->priv->key_file, section, key, NULL, NULL);
283 }
284
285 void
286 config_set_integer (Configuration *config, const gchar *section, const gchar *key, gint value)
287 {
288     g_key_file_set_integer (config->priv->key_file, section, key, value);
289 }
290
291 gint
292 config_get_integer (Configuration *config, const gchar *section, const gchar *key)
293 {
294     return g_key_file_get_integer (config->priv->key_file, section, key, NULL);
295 }
296
297 void
298 config_set_boolean (Configuration *config, const gchar *section, const gchar *key, gboolean value)
299 {
300     g_key_file_set_boolean (config->priv->key_file, section, key, value);
301 }
302
303 gboolean
304 config_get_boolean (Configuration *config, const gchar *section, const gchar *key)
305 {
306     return g_key_file_get_boolean (config->priv->key_file, section, key, NULL);
307 }
308
309 static void
310 config_init (Configuration *config)
311 {
312     config->priv = G_TYPE_INSTANCE_GET_PRIVATE (config, CONFIGURATION_TYPE, ConfigurationPrivate);
313     config->priv->key_file = g_key_file_new ();
314     config->priv->key_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
315 }
316
317 static void
318 config_finalize (GObject *object)
319 {
320     Configuration *self;
321
322     self = CONFIGURATION (object);
323
324     g_free (self->priv->dir);
325     g_key_file_free (self->priv->key_file);
326     g_list_free_full (self->priv->sources, g_free);
327     g_hash_table_destroy (self->priv->key_sources);
328
329     G_OBJECT_CLASS (config_parent_class)->finalize (object);  
330 }
331
332 static void
333 config_class_init (ConfigurationClass *klass)
334 {
335     GObjectClass *object_class = G_OBJECT_CLASS (klass);
336
337     object_class->finalize = config_finalize;  
338
339     g_type_class_add_private (klass, sizeof (ConfigurationPrivate));
340 }