]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - common/configuration.c
Scan XDG_DATA_DIRS and XDG_CONFIG_DIRS for config values too
[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     GKeyFile *key_file;
19 };
20
21 G_DEFINE_TYPE (Configuration, config, G_TYPE_OBJECT);
22
23 static Configuration *configuration_instance = NULL;
24
25 Configuration *
26 config_get_instance (void)
27 {
28     if (!configuration_instance)
29         configuration_instance = g_object_new (CONFIGURATION_TYPE, NULL);
30     return configuration_instance;
31 }
32
33 gboolean
34 config_load_from_file (Configuration *config, const gchar *path, GError **error)
35 {
36     GKeyFile *key_file;
37     gchar **groups;
38     int i;
39
40     key_file = g_key_file_new ();
41     if (!g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, error))
42     {
43         g_key_file_free (key_file);
44         return FALSE;
45     }
46
47     groups = g_key_file_get_groups (key_file, NULL);
48     for (i = 0; groups[i]; i++)
49     {
50         gchar **keys;
51         int j;
52
53         keys = g_key_file_get_keys (key_file, groups[i], NULL, error);
54         if (!keys)
55             break;
56       
57         for (j = 0; keys[j]; j++)
58         {
59             gchar *value;
60
61             value = g_key_file_get_value (key_file, groups[i], keys[j], NULL);
62             g_key_file_set_value (config->priv->key_file, groups[i], keys[j], value);
63             g_free (value);
64         }
65
66         g_strfreev (keys);
67     }
68     g_strfreev (groups);
69
70     g_key_file_free (key_file);
71
72     return TRUE;
73 }
74
75 static gchar *
76 path_make_absolute (gchar *path)
77 {
78     gchar *cwd, *abs_path;
79
80     if (!path)
81         return NULL;
82
83     if (g_path_is_absolute (path))
84         return path;
85
86     cwd = g_get_current_dir ();
87     abs_path = g_build_filename (cwd, path, NULL);
88     g_free (path);
89
90     return abs_path;
91 }
92
93 static int
94 compare_strings (gconstpointer a, gconstpointer b)
95 {
96     return strcmp (a, b);
97 }
98
99 static void
100 load_config_directory (const gchar *path, GList **messages)
101 {
102     GDir *dir;
103     GList *files = NULL, *link;
104     GError *error = NULL;
105
106     /* Find configuration files */
107     dir = g_dir_open (path, 0, &error);
108     if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
109         g_printerr ("Failed to open configuration directory %s: %s\n", path, error->message);
110     g_clear_error (&error);
111     if (dir)
112     {
113         const gchar *name;
114         while ((name = g_dir_read_name (dir)))
115             files = g_list_append (files, g_strdup (name));
116         g_dir_close (dir);
117     }
118
119     /* Sort alphabetically and load onto existing configuration */
120     files = g_list_sort (files, compare_strings);
121     for (link = files; link; link = link->next)
122     {
123         gchar *filename = link->data;
124         gchar *conf_path;
125
126         conf_path = g_build_filename (path, filename, NULL);
127         if (g_str_has_suffix (filename, ".conf"))
128         {
129             if (messages)
130                 *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration from %s", conf_path));
131             config_load_from_file (config_get_instance (), conf_path, &error);
132             if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
133                 g_printerr ("Failed to load configuration from %s: %s\n", filename, error->message);
134             g_clear_error (&error);
135         }
136         else
137             g_debug ("Ignoring configuration file %s, it does not have .conf suffix", conf_path);
138         g_free (conf_path);
139     }
140     g_list_free_full (files, g_free);
141 }
142
143 static void
144 load_config_directories (const gchar * const *dirs, GList **messages)
145 {
146     gint i;
147
148     for (i = 0; dirs[i]; i++)
149     {
150         gchar *full_dir = g_build_filename (dirs[i], "lightdm", "lightdm.conf.d", NULL);
151             if (messages)
152                 *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration dirs from %s", full_dir));
153         load_config_directory (full_dir, messages);
154         g_free (full_dir);
155     }
156 }
157
158 gboolean
159 config_load_from_standard_locations (Configuration *config, const gchar *config_path, GList **messages)
160 {
161     gchar *config_dir, *config_d_dir = NULL;
162     gboolean explicit_config = FALSE;
163     gboolean success = TRUE;
164     GError *error = NULL;
165
166     load_config_directories (g_get_system_data_dirs (), messages);
167     load_config_directories (g_get_system_config_dirs (), messages);
168
169     if (config_path)
170     {
171         config_dir = g_path_get_basename (config_path);
172         config_dir = path_make_absolute (config_dir);
173         explicit_config = TRUE;
174     }
175     else
176     {
177         config_dir = g_strdup (CONFIG_DIR);
178         config_d_dir = g_build_filename (config_dir, "lightdm.conf.d", NULL);
179         config_path = g_build_filename (config_dir, "lightdm.conf", NULL);
180     }
181     config_set_string (config, "LightDM", "config-directory", config_dir);
182     g_free (config_dir);
183
184     if (config_d_dir)
185         load_config_directory (config_d_dir, messages);
186     g_free (config_d_dir);
187
188     if (messages)
189         *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration from %s", config_path));
190     if (!config_load_from_file (config, config_path, &error))
191     {
192         gboolean is_empty;
193
194         is_empty = error && g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
195
196         if (explicit_config || !is_empty)
197         {
198             if (error)
199                 g_printerr ("Failed to load configuration from %s: %s\n", config_path, error->message);
200             success = FALSE;
201         }
202     }
203     g_clear_error (&error);
204
205     return success;
206 }
207
208 gchar **
209 config_get_groups (Configuration *config)
210 {
211     return g_key_file_get_groups (config->priv->key_file, NULL);
212 }
213
214 gchar **
215 config_get_keys (Configuration *config, const gchar *group_name)
216 {
217     return g_key_file_get_keys (config->priv->key_file, group_name, NULL, NULL);
218 }
219
220 gboolean
221 config_has_key (Configuration *config, const gchar *section, const gchar *key)
222 {
223     return g_key_file_has_key (config->priv->key_file, section, key, NULL);
224 }
225
226 void
227 config_set_string (Configuration *config, const gchar *section, const gchar *key, const gchar *value)
228 {
229     g_key_file_set_string (config->priv->key_file, section, key, value);
230 }
231
232 gchar *
233 config_get_string (Configuration *config, const gchar *section, const gchar *key)
234 {
235     return g_key_file_get_string (config->priv->key_file, section, key, NULL);
236 }
237
238 void
239 config_set_string_list (Configuration *config, const gchar *section, const gchar *key, const gchar **value, gsize length)
240 {
241     g_key_file_set_string_list (config->priv->key_file, section, key, value, length);
242 }
243
244 gchar **
245 config_get_string_list (Configuration *config, const gchar *section, const gchar *key)
246 {
247     return g_key_file_get_string_list (config->priv->key_file, section, key, NULL, NULL);
248 }
249
250 void
251 config_set_integer (Configuration *config, const gchar *section, const gchar *key, gint value)
252 {
253     g_key_file_set_integer (config->priv->key_file, section, key, value);
254 }
255
256 gint
257 config_get_integer (Configuration *config, const gchar *section, const gchar *key)
258 {
259     return g_key_file_get_integer (config->priv->key_file, section, key, NULL);
260 }
261
262 void
263 config_set_boolean (Configuration *config, const gchar *section, const gchar *key, gboolean value)
264 {
265     g_key_file_set_boolean (config->priv->key_file, section, key, value);
266 }
267
268 gboolean
269 config_get_boolean (Configuration *config, const gchar *section, const gchar *key)
270 {
271     return g_key_file_get_boolean (config->priv->key_file, section, key, NULL);
272 }
273
274 static void
275 config_init (Configuration *config)
276 {
277     config->priv = G_TYPE_INSTANCE_GET_PRIVATE (config, CONFIGURATION_TYPE, ConfigurationPrivate);
278     config->priv->key_file = g_key_file_new ();  
279 }
280
281 static void
282 config_finalize (GObject *object)
283 {
284     Configuration *self;
285
286     self = CONFIGURATION (object);
287
288     g_key_file_free (self->priv->key_file);
289
290     G_OBJECT_CLASS (config_parent_class)->finalize (object);  
291 }
292
293 static void
294 config_class_init (ConfigurationClass *klass)
295 {
296     GObjectClass *object_class = G_OBJECT_CLASS (klass);
297
298     object_class->finalize = config_finalize;  
299
300     g_type_class_add_private (klass, sizeof (ConfigurationPrivate));
301 }