]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - common/configuration.c
Launchpad automatic translations update.
[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, GList **messages, 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, *group;
57         int j;
58
59         /* Move keys from deprecated [SeatDefaults] into [Seat:*] */
60         group = groups[i];
61         if (strcmp (group, "SeatDefaults") == 0)
62         {
63             if (messages)
64                 *messages = g_list_append (*messages, g_strdup ("  [SeatDefaults] is now called [Seat:*], please update this configuration"));
65             group = "Seat:*";
66         }
67
68         keys = g_key_file_get_keys (key_file, groups[i], NULL, error);
69         if (!keys)
70             break;
71
72         for (j = 0; keys[j]; j++)
73         {
74             gchar *value, *k;
75
76             if (messages && g_str_has_prefix (group, "Seat:") && strcmp (keys[j], "xdg-seat") == 0)
77                 *messages = g_list_append (*messages, g_strdup_printf ("  [%s] contains deprecated option xdg-seat, this can be safely removed", group));
78             if (messages && strcmp (group, "LightDM") == 0 && strcmp (keys[j], "logind-load-seats") == 0)
79                 *messages = g_list_append (*messages, g_strdup ("  [LightDM] contains deprecated option logind-load-seats, this can be safely removed"));
80
81             value = g_key_file_get_value (key_file, groups[i], keys[j], NULL);
82             g_key_file_set_value (config->priv->key_file, group, keys[j], value);
83             g_free (value);
84
85             k = g_strdup_printf ("%s]%s", group, keys[j]);
86             g_hash_table_insert (config->priv->key_sources, k, source_path);
87         }
88
89         g_strfreev (keys);
90     }
91     g_strfreev (groups);
92
93     g_key_file_free (key_file);
94
95     return TRUE;
96 }
97
98 static gchar *
99 path_make_absolute (gchar *path)
100 {
101     gchar *cwd, *abs_path;
102
103     if (!path)
104         return NULL;
105
106     if (g_path_is_absolute (path))
107         return path;
108
109     cwd = g_get_current_dir ();
110     abs_path = g_build_filename (cwd, path, NULL);
111     g_free (path);
112
113     return abs_path;
114 }
115
116 static int
117 compare_strings (gconstpointer a, gconstpointer b)
118 {
119     return strcmp (a, b);
120 }
121
122 static void
123 load_config_directory (const gchar *path, GList **messages)
124 {
125     GDir *dir;
126     GList *files = NULL, *link;
127     GError *error = NULL;
128
129     /* Find configuration files */
130     dir = g_dir_open (path, 0, &error);
131     if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
132         g_printerr ("Failed to open configuration directory %s: %s\n", path, error->message);
133     g_clear_error (&error);
134     if (dir)
135     {
136         const gchar *name;
137         while ((name = g_dir_read_name (dir)))
138             files = g_list_append (files, g_strdup (name));
139         g_dir_close (dir);
140     }
141
142     /* Sort alphabetically and load onto existing configuration */
143     files = g_list_sort (files, compare_strings);
144     for (link = files; link; link = link->next)
145     {
146         gchar *filename = link->data;
147         gchar *conf_path;
148
149         conf_path = g_build_filename (path, filename, NULL);
150         if (g_str_has_suffix (filename, ".conf"))
151         {
152             if (messages)
153                 *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration from %s", conf_path));
154             config_load_from_file (config_get_instance (), conf_path, messages, &error);
155             if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
156                 g_printerr ("Failed to load configuration from %s: %s\n", filename, error->message);
157             g_clear_error (&error);
158         }
159         else
160             g_debug ("Ignoring configuration file %s, it does not have .conf suffix", conf_path);
161         g_free (conf_path);
162     }
163     g_list_free_full (files, g_free);
164 }
165
166 static void
167 load_config_directories (const gchar * const *dirs, GList **messages)
168 {
169     gint i;
170
171     /* Load in reverse order, because XDG_* fields are preference-ordered and the directories in front should override directories in back. */
172     for (i = g_strv_length ((gchar **)dirs) - 1; i >= 0; i--)
173     {
174         gchar *full_dir = g_build_filename (dirs[i], "lightdm", "lightdm.conf.d", NULL);
175         if (messages)
176             *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration dirs from %s", full_dir));
177         load_config_directory (full_dir, messages);
178         g_free (full_dir);
179     }
180 }
181
182 gboolean
183 config_load_from_standard_locations (Configuration *config, const gchar *config_path, GList **messages)
184 {
185     gchar *config_d_dir = NULL, *path;
186     gboolean success = TRUE;
187     GError *error = NULL;
188
189     g_return_val_if_fail (config->priv->dir == NULL, FALSE);
190
191     load_config_directories (g_get_system_data_dirs (), messages);
192     load_config_directories (g_get_system_config_dirs (), messages);
193
194     if (config_path)
195     {
196         path = g_strdup (config_path);
197         config->priv->dir = path_make_absolute (g_path_get_basename (config_path));
198     }
199     else
200     {
201         config->priv->dir = g_strdup (CONFIG_DIR);
202         config_d_dir = g_build_filename (config->priv->dir, "lightdm.conf.d", NULL);
203         path = g_build_filename (config->priv->dir, "lightdm.conf", NULL);
204     }
205
206     if (config_d_dir)
207         load_config_directory (config_d_dir, messages);
208
209     if (messages)
210         *messages = g_list_append (*messages, g_strdup_printf ("Loading configuration from %s", path));
211     if (!config_load_from_file (config, path, messages, &error))
212     {
213         gboolean is_empty;
214
215         is_empty = error && g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
216
217         if (config_path || !is_empty)
218         {
219             if (error)
220                 g_printerr ("Failed to load configuration from %s: %s\n", path, error->message);
221             success = FALSE;
222         }
223     }
224     g_clear_error (&error);
225
226     g_free (config_d_dir);
227     g_free (path);
228
229     return success;
230 }
231
232 const gchar *
233 config_get_directory (Configuration *config)
234 {
235     return config->priv->dir;
236 }
237
238 gchar **
239 config_get_groups (Configuration *config)
240 {
241     return g_key_file_get_groups (config->priv->key_file, NULL);
242 }
243
244 gchar **
245 config_get_keys (Configuration *config, const gchar *group_name)
246 {
247     return g_key_file_get_keys (config->priv->key_file, group_name, NULL, NULL);
248 }
249
250 gboolean
251 config_has_key (Configuration *config, const gchar *section, const gchar *key)
252 {
253     return g_key_file_has_key (config->priv->key_file, section, key, NULL);
254 }
255
256 GList *
257 config_get_sources (Configuration *config)
258 {
259     return config->priv->sources;
260 }
261
262 const gchar *
263 config_get_source (Configuration *config, const gchar *section, const gchar *key)
264 {
265     gchar *k;
266     const gchar *source;
267
268     k = g_strdup_printf ("%s]%s", section, key);
269     source = g_hash_table_lookup (config->priv->key_sources, k);
270     g_free (k);
271
272     return source;
273 }
274
275 void
276 config_set_string (Configuration *config, const gchar *section, const gchar *key, const gchar *value)
277 {
278     g_key_file_set_string (config->priv->key_file, section, key, value);
279 }
280
281 gchar *
282 config_get_string (Configuration *config, const gchar *section, const gchar *key)
283 {
284     return g_key_file_get_string (config->priv->key_file, section, key, NULL);
285 }
286
287 void
288 config_set_string_list (Configuration *config, const gchar *section, const gchar *key, const gchar **value, gsize length)
289 {
290     g_key_file_set_string_list (config->priv->key_file, section, key, value, length);
291 }
292
293 gchar **
294 config_get_string_list (Configuration *config, const gchar *section, const gchar *key)
295 {
296     return g_key_file_get_string_list (config->priv->key_file, section, key, NULL, NULL);
297 }
298
299 void
300 config_set_integer (Configuration *config, const gchar *section, const gchar *key, gint value)
301 {
302     g_key_file_set_integer (config->priv->key_file, section, key, value);
303 }
304
305 gint
306 config_get_integer (Configuration *config, const gchar *section, const gchar *key)
307 {
308     return g_key_file_get_integer (config->priv->key_file, section, key, NULL);
309 }
310
311 void
312 config_set_boolean (Configuration *config, const gchar *section, const gchar *key, gboolean value)
313 {
314     g_key_file_set_boolean (config->priv->key_file, section, key, value);
315 }
316
317 gboolean
318 config_get_boolean (Configuration *config, const gchar *section, const gchar *key)
319 {
320     /* We don't use the standard function because it doesn't work with trailing whitespace:
321      * https://bugzilla.gnome.org/show_bug.cgi?id=664740
322      */
323     /*return g_key_file_get_boolean (config->priv->key_file, section, key, NULL);*/
324
325     gchar *value;
326     gboolean v;
327
328     value = g_key_file_get_value (config->priv->key_file, section, key, NULL);
329     if (!value)
330         return FALSE;
331     g_strchomp (value);
332     v = strcmp (value, "true") == 0;
333     g_free (value);
334
335     return v;
336 }
337
338 static void
339 config_init (Configuration *config)
340 {
341     config->priv = G_TYPE_INSTANCE_GET_PRIVATE (config, CONFIGURATION_TYPE, ConfigurationPrivate);
342     config->priv->key_file = g_key_file_new ();
343     config->priv->key_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
344 }
345
346 static void
347 config_finalize (GObject *object)
348 {
349     Configuration *self = CONFIGURATION (object);
350
351     g_free (self->priv->dir);
352     g_key_file_free (self->priv->key_file);
353     g_list_free_full (self->priv->sources, g_free);
354     g_hash_table_destroy (self->priv->key_sources);
355
356     G_OBJECT_CLASS (config_parent_class)->finalize (object);  
357 }
358
359 static void
360 config_class_init (ConfigurationClass *klass)
361 {
362     GObjectClass *object_class = G_OBJECT_CLASS (klass);
363
364     object_class->finalize = config_finalize;  
365
366     g_type_class_add_private (klass, sizeof (ConfigurationPrivate));
367 }