]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - common/configuration.c
Whoops, add new scripts and test files to tests/Makefile.am
[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     /* Load in reverse order, because XDG_* fields are preference-ordered and the directories in front should override directories in back. */
149     for (i = g_strv_length ((gchar **)dirs) - 1; i >= 0; i--)
150     {
151         gchar *full_dir = g_build_filename (dirs[i], "lightdm", "lightdm.conf.d", NULL);
152         if (messages)
153             *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration dirs from %s", full_dir));
154         load_config_directory (full_dir, messages);
155         g_free (full_dir);
156     }
157 }
158
159 gboolean
160 config_load_from_standard_locations (Configuration *config, const gchar *config_path, GList **messages)
161 {
162     gchar *config_dir, *config_d_dir = NULL;
163     gboolean explicit_config = FALSE;
164     gboolean success = TRUE;
165     GError *error = NULL;
166
167     load_config_directories (g_get_system_data_dirs (), messages);
168     load_config_directories (g_get_system_config_dirs (), messages);
169
170     if (config_path)
171     {
172         config_dir = g_path_get_basename (config_path);
173         config_dir = path_make_absolute (config_dir);
174         explicit_config = TRUE;
175     }
176     else
177     {
178         config_dir = g_strdup (CONFIG_DIR);
179         config_d_dir = g_build_filename (config_dir, "lightdm.conf.d", NULL);
180         config_path = g_build_filename (config_dir, "lightdm.conf", NULL);
181     }
182     config_set_string (config, "LightDM", "config-directory", config_dir);
183     g_free (config_dir);
184
185     if (config_d_dir)
186         load_config_directory (config_d_dir, messages);
187     g_free (config_d_dir);
188
189     if (messages)
190         *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration from %s", config_path));
191     if (!config_load_from_file (config, config_path, &error))
192     {
193         gboolean is_empty;
194
195         is_empty = error && g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
196
197         if (explicit_config || !is_empty)
198         {
199             if (error)
200                 g_printerr ("Failed to load configuration from %s: %s\n", config_path, error->message);
201             success = FALSE;
202         }
203     }
204     g_clear_error (&error);
205
206     return success;
207 }
208
209 gchar **
210 config_get_groups (Configuration *config)
211 {
212     return g_key_file_get_groups (config->priv->key_file, NULL);
213 }
214
215 gchar **
216 config_get_keys (Configuration *config, const gchar *group_name)
217 {
218     return g_key_file_get_keys (config->priv->key_file, group_name, NULL, NULL);
219 }
220
221 gboolean
222 config_has_key (Configuration *config, const gchar *section, const gchar *key)
223 {
224     return g_key_file_has_key (config->priv->key_file, section, key, NULL);
225 }
226
227 void
228 config_set_string (Configuration *config, const gchar *section, const gchar *key, const gchar *value)
229 {
230     g_key_file_set_string (config->priv->key_file, section, key, value);
231 }
232
233 gchar *
234 config_get_string (Configuration *config, const gchar *section, const gchar *key)
235 {
236     return g_key_file_get_string (config->priv->key_file, section, key, NULL);
237 }
238
239 void
240 config_set_string_list (Configuration *config, const gchar *section, const gchar *key, const gchar **value, gsize length)
241 {
242     g_key_file_set_string_list (config->priv->key_file, section, key, value, length);
243 }
244
245 gchar **
246 config_get_string_list (Configuration *config, const gchar *section, const gchar *key)
247 {
248     return g_key_file_get_string_list (config->priv->key_file, section, key, NULL, NULL);
249 }
250
251 void
252 config_set_integer (Configuration *config, const gchar *section, const gchar *key, gint value)
253 {
254     g_key_file_set_integer (config->priv->key_file, section, key, value);
255 }
256
257 gint
258 config_get_integer (Configuration *config, const gchar *section, const gchar *key)
259 {
260     return g_key_file_get_integer (config->priv->key_file, section, key, NULL);
261 }
262
263 void
264 config_set_boolean (Configuration *config, const gchar *section, const gchar *key, gboolean value)
265 {
266     g_key_file_set_boolean (config->priv->key_file, section, key, value);
267 }
268
269 gboolean
270 config_get_boolean (Configuration *config, const gchar *section, const gchar *key)
271 {
272     return g_key_file_get_boolean (config->priv->key_file, section, key, NULL);
273 }
274
275 static void
276 config_init (Configuration *config)
277 {
278     config->priv = G_TYPE_INSTANCE_GET_PRIVATE (config, CONFIGURATION_TYPE, ConfigurationPrivate);
279     config->priv->key_file = g_key_file_new ();  
280 }
281
282 static void
283 config_finalize (GObject *object)
284 {
285     Configuration *self;
286
287     self = CONFIGURATION (object);
288
289     g_key_file_free (self->priv->key_file);
290
291     G_OBJECT_CLASS (config_parent_class)->finalize (object);  
292 }
293
294 static void
295 config_class_init (ConfigurationClass *klass)
296 {
297     GObjectClass *object_class = G_OBJECT_CLASS (klass);
298
299     object_class->finalize = config_finalize;  
300
301     g_type_class_add_private (klass, sizeof (ConfigurationPrivate));
302 }