First tlm release
[platform/core/system/tlm.git] / src / common / tlm-config.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of tlm
5  *
6  * Copyright (C) 2013-2014 Intel Corporation.
7  *
8  * Contact: Imran Zaman <imran.zaman@intel.com>
9  *          Amarnath Valluri <amarnath.valluri@linux.intel.com>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24  * 02110-1301 USA
25  */
26
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <glib/gstdio.h>
30
31 #include "config.h"
32 #include "tlm-config.h"
33 #include "tlm-config-general.h"
34 #include "tlm-log.h"
35
36 /**
37  * SECTION:tlm-config
38  * @short_description: tlm configuration information
39  * @include: tlm-config.h
40  *
41  * #TlmConfig holds configuration information as a set of keys and values
42  * (integer or strings). The key names are defined in
43  * <link linkend="tlm-General-configuration">General config keys</link>.
44  * Note that authentication and account plugins may use plugin-specific
45  * configuration keys; see plugins' documentation for specifics.
46  *
47  * The configuration is retrieved from the tlm configuration file. See below
48  * for where the file is searched for.
49  *
50  * <refsect1><title>Usage</title></refsect1>
51  * Following code snippet demonstrates how to create and use config object:
52  * |[
53  *
54  * TlmConfig* config = tlm_config_new ();
55  * const gchar *str = tlm_config_get_string (config,
56  *  TLM_CONFIG_GENERAL, TLM_CONFIG_GENERAL_PAM_SERVICE, 0);
57  * g_object_unref(config);
58  *
59  * ]|
60  *
61  * <refsect1><title>Where the configuration file is searched for</title>
62  * </refsect1>
63  *
64  * If tlm has been compiled with --enable-debug, then these locations are used,
65  * in decreasing order of priority:
66  * - TLM_CONF_FILE environment variable
67  * - g_get_user_config_dir() + "tlm.conf"
68  * - each of g_get_system_config_dirs() + "tlm.conf"
69  *
70  * Otherwise, the config file location is determined at compilation time as
71  * $(sysconfdir) + "tlm.conf"
72  *
73  * <refsect1><title>Example configuration file</title></refsect1>
74  *
75  * See example configuration file here:
76  * <ulink url="https://github.com/01org/tlm/blob/master/data/tlm.conf.in">
77  * tlm configuration file</ulink>
78  *
79  */
80
81 /**
82  * TlmConfig:
83  *
84  * Opaque structure for the object.
85  */
86
87 /**
88  * TlmConfigClass:
89  * @parent_class: parent class object
90  *
91  * Opaque structure for the class.
92  */
93
94 struct _TlmConfigPrivate
95 {
96     gchar *config_file_path;
97     GHashTable *config_table;
98 };
99
100 #define TLM_CONFIG_PRIV(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
101         TLM_TYPE_CONFIG, TlmConfigPrivate)
102
103 G_DEFINE_TYPE (TlmConfig, tlm_config, G_TYPE_OBJECT);
104
105 static gboolean
106 _load_config (
107         TlmConfig *self)
108 {
109     gchar *def_config;
110     GError *err = NULL;
111     gchar **groups = NULL;
112     gsize n_groups = 0;
113     int i,j;
114     GKeyFile *settings = g_key_file_new ();
115
116 #   ifdef ENABLE_DEBUG
117     const gchar * const *sysconfdirs;
118
119     if (!self->priv->config_file_path) {
120         def_config = g_strdup (g_getenv ("TLM_CONF_FILE"));
121         if (!def_config)
122             def_config = g_build_filename (g_get_user_config_dir(),
123                                            "/tlm.conf",
124                                            NULL);
125         if (g_access (def_config, R_OK) == 0) {
126             self->priv->config_file_path = def_config;
127         } else {
128             g_free (def_config);
129             sysconfdirs = g_get_system_config_dirs ();
130             while (*sysconfdirs != NULL) {
131                 def_config = g_build_filename (*sysconfdirs,
132                                                "/tlm.conf",
133                                                NULL);
134                 if (g_access (def_config, R_OK) == 0) {
135                     self->priv->config_file_path = def_config;
136                     break;
137                 }
138                 g_free (def_config);
139                 sysconfdirs++;
140             }
141         }
142     }
143 #   else  /* ENABLE_DEBUG */
144 #   ifndef TLM_SYSCONF_DIR
145 #   error "System configuration directory not defined!"
146 #   endif
147     def_config = g_build_filename (TLM_SYSCONF_DIR,
148                                    "/tlm.conf",
149                                    NULL);
150     if (g_access (def_config, R_OK) == 0) {
151         self->priv->config_file_path = def_config;
152     } else {
153         g_free (def_config);
154     }
155 #   endif  /* ENABLE_DEBUG */
156
157     if (self->priv->config_file_path) {
158         DBG ("Loading TLM config from %s", self->priv->config_file_path);
159         if (!g_key_file_load_from_file (settings,
160                                         self->priv->config_file_path,
161                                         G_KEY_FILE_NONE, &err)) {
162             WARN ("error reading config file at '%s': %s",
163                  self->priv->config_file_path, err->message);
164             g_error_free (err);
165             g_key_file_free (settings);
166             return FALSE;
167         }
168     }
169     else {
170         WARN ("No valid configuration file found");
171         return FALSE;
172     }
173
174     groups = g_key_file_get_groups (settings, &n_groups);
175
176     for (i = 0; i < n_groups; i++) {
177         GError *err = NULL;
178         gsize n_keys =0;
179         GHashTable *group_table = NULL;
180         gchar **keys = g_key_file_get_keys (settings,
181                                             groups[i],
182                                             &n_keys,
183                                             &err);
184         if (err) {
185             WARN ("fail to read group '%s': %s", groups[i], err->message);
186             g_error_free (err);
187             continue;
188         }
189
190         group_table = (GHashTable *) g_hash_table_lookup (
191                                 self->priv->config_table, groups[i]);
192         if (!group_table) 
193             group_table = g_hash_table_new_full (
194                                g_str_hash,
195                                g_str_equal,
196                                g_free,
197                                (GDestroyNotify)g_free);
198
199         for (j = 0; j < n_keys; j++) {
200             gchar *value = g_key_file_get_value (settings,
201                                                  groups[i],
202                                                  keys[j],
203                                                  &err);
204             if (err) {
205                 WARN ("fail to read key '%s/%s': %s", groups[i], keys[j],
206                         err->message);
207                 g_error_free (err);
208                 continue;
209             }
210
211             DBG ("found config : '%s/%s' - '%s'", groups[i], keys[j], value);
212
213             g_hash_table_insert (group_table,
214                                  (gpointer)g_strdup (keys[j]),
215                                  (gpointer)value);
216
217         }
218
219         g_hash_table_insert (self->priv->config_table,
220                              g_strdup (groups[i]),
221                              group_table);
222
223         g_strfreev (keys);
224     }
225
226     g_strfreev (groups);
227
228     g_key_file_free (settings);
229
230     return TRUE;
231 }
232
233 #ifdef ENABLE_DEBUG
234 static void
235 _load_environment (
236         TlmConfig *self)
237 {
238     const gchar *e_val = 0;
239     
240     e_val = g_getenv("TLM_ACCOUNT_PLUGIN");
241     if (e_val)
242         tlm_config_set_string (self, 
243                                TLM_CONFIG_GENERAL, 
244                                TLM_CONFIG_GENERAL_ACCOUNTS_PLUGIN, e_val);
245 }
246 #endif  /* ENABLE_DEBUG */
247
248 static void
249 _set_defaults (
250         TlmConfig *self)
251 {
252
253     /* accounts plugin => default */
254     if (!tlm_config_has_key (self,
255                              TLM_CONFIG_GENERAL,
256                              TLM_CONFIG_GENERAL_ACCOUNTS_PLUGIN)) {
257         tlm_config_set_string (self,
258                                TLM_CONFIG_GENERAL,
259                                TLM_CONFIG_GENERAL_ACCOUNTS_PLUGIN,
260                                "default");
261     }
262
263     /* default PAM service => tlm-login */
264     if (!tlm_config_has_key (self,
265                              TLM_CONFIG_GENERAL,
266                              TLM_CONFIG_GENERAL_PAM_SERVICE)) {
267         tlm_config_set_string (self,
268                                TLM_CONFIG_GENERAL,
269                                TLM_CONFIG_GENERAL_PAM_SERVICE,
270                                "tlm-login");
271     }
272
273     /* default user => guest */
274     if (!tlm_config_has_key (self,
275                              TLM_CONFIG_GENERAL,
276                              TLM_CONFIG_GENERAL_DEFAULT_USER)) {
277         tlm_config_set_string (self,
278                                TLM_CONFIG_GENERAL,
279                                TLM_CONFIG_GENERAL_DEFAULT_USER,
280                                "guest");
281     }
282 }
283
284 /**
285  * tlm_config_get_group:
286  * @self: (transfer none): an instance of #TlmConfig
287  * @group: the group name
288  *
289  * Retrives the configuration in given #group as #GHashTable
290  *
291  * Returns: (transfer none): the key, value paired dictionary if found,
292  * NULL otherwise.
293  */
294 GHashTable *
295 tlm_config_get_group (
296         TlmConfig *self,
297         const gchar *group)
298 {
299     g_return_val_if_fail (self && TLM_IS_CONFIG(self), NULL);
300     g_return_val_if_fail (group && group[0], NULL);
301
302     return (GHashTable *) g_hash_table_lookup (self->priv->config_table,
303                                                   group);
304 }
305
306 /**
307  * tlm_config_get_string:
308  * @self: (transfer none): an instance of #TlmConfig
309  * @group: (transfer none): the group name, NULL refers to General
310  * @key: (transfer none): the key name
311  *
312  * Get a string configuration value.
313  *
314  * Returns: the value corresponding to the key as an string. If the
315  * key does not exist or cannot be converted to the integer, NULL is returned.
316  */
317 const gchar *
318 tlm_config_get_string (
319         TlmConfig *self,
320         const gchar *group,
321         const gchar *key)
322 {
323     g_return_val_if_fail (self && TLM_IS_CONFIG (self), NULL);
324     g_return_val_if_fail (key && key[0], NULL);
325
326     GHashTable *group_table = tlm_config_get_group (self, group);
327     if (!group_table) return NULL;
328
329     return (const gchar *) g_hash_table_lookup (group_table, key);
330 }
331
332 /**
333  * tlm_config_set_string:
334  * @self: (transfer none): an instance of #TlmConfig
335  * @group: (transfer none): the group name
336  * @key: (transfer none): the key name
337  * @value: (transfer none): the value
338  *
339  * Sets the configuration value to the provided string.
340  */
341 void
342 tlm_config_set_string (
343         TlmConfig *self,
344         const gchar *group,
345         const gchar *key,
346         const gchar *value)
347 {
348     g_return_if_fail (self && TLM_IS_CONFIG (self));
349     g_return_if_fail (key && key[0]);
350
351     if (!group) group = TLM_CONFIG_GENERAL;
352
353     GHashTable *group_table = tlm_config_get_group (self, group);
354     if (!group_table) {
355         group_table = g_hash_table_new_full (g_str_hash,
356                                              g_str_equal,
357                                              g_free,
358                                              g_free);
359         g_hash_table_insert (self->priv->config_table,
360                              (gpointer)g_strdup (group),
361                              (gpointer)group_table);
362     }
363
364     g_hash_table_insert (group_table,
365                          (gpointer) g_strdup (key),
366                          (gpointer) g_strdup (value));
367
368 }
369 /**
370  * tlm_config_get_int:
371  * @self: (transfer none): an instance of #TlmConfig
372  * @group: the group name
373  * @key: the key name
374  * @retval: value to be returned in case key is not found
375  *
376  * Get an integer configuration value.
377  *
378  * Returns: the value corresponding to the key as an integer. If the key does
379  * not exist or cannot be converted to the integer, retval is returned.
380  */
381 gint
382 tlm_config_get_int (
383         TlmConfig *self,
384         const gchar *group,
385         const gchar *key,
386         gint retval)
387 {
388     const gchar *str_value = tlm_config_get_string (self, group, key);
389     return (gint) (str_value ? atoi (str_value) : retval);
390 }
391
392 /**
393  * tlm_config_set_int:
394  * @self: (transfer none): an instance of #TlmConfig
395  * @group: the group name
396  * @key: the key name
397  * @value: the value
398  *
399  * Sets the configuration value to the provided integer.
400  */
401 void
402 tlm_config_set_int (
403         TlmConfig *self,
404         const gchar *group,
405         const gchar *key,
406         gint value)
407 {
408     gchar *s_value = 0;
409     g_return_if_fail (self && TLM_IS_CONFIG (self));
410
411     s_value = g_strdup_printf ("%d", value);
412     if (!s_value) return;
413
414     tlm_config_set_string (self, group, key, s_value);
415
416     g_free (s_value);
417 }
418
419 /**
420  * tlm_config_get_uint:
421  * @self: (transfer none): an instance of #TlmConfig
422  * @group: (transfer none): the group name
423  * @key: (transfer none): the key name
424  * @retval: value to be returned in case key is not found
425  *
426  * Get an unsigned integer configuration value.
427  *
428  * Returns: the value corresponding to the key as an unsigned integer. If the
429  * key does not exist or cannot be converted to the integer, retval is returned.
430  */
431 guint
432 tlm_config_get_uint (
433         TlmConfig *self,
434         const gchar *group,
435         const gchar *key,
436         guint retval)
437 {
438     guint value;
439     const gchar *str_value = tlm_config_get_string (self, group, key);
440     if (!str_value || sscanf (str_value, "%u", &value) <= 0) value = retval;
441
442     return value;
443 }
444
445 /**
446  * tlm_config_set_uint:
447  * @self: (transfer none): an instance of #TlmConfig
448  * @group: (transfer none):  the group name
449  * @key: the key name
450  * @value: the value
451  *
452  * Sets the configuration value to the provided unsigned integer.
453  */
454 void
455 tlm_config_set_uint (
456         TlmConfig *self,
457         const gchar *group,
458         const gchar *key,
459         guint value)
460 {
461     gchar *s_value = 0;
462     g_return_if_fail (self && TLM_IS_CONFIG (self));
463
464     s_value = g_strdup_printf ("%u", value);
465     if (!s_value) return;
466
467     tlm_config_set_string (self, group, key, s_value);
468     g_free (s_value);
469 }
470
471 /**
472  * tlm_config_get_boolean:
473  * @self: (transfer none): an instance of #TlmConfig
474  * @group: (transfer none): the group name
475  * @key: (transfer none): the key name
476  * @retval: value to be returned in case key is not found
477  *
478  * Get a boolean configuration value.
479  *
480  * Returns: the value corresponding to the key as boolean. If the
481  * key does not exist or cannot be converted to boolean, retval is returned.
482  */
483 gboolean
484 tlm_config_get_boolean (
485         TlmConfig *self,
486         const gchar *group,
487         const gchar *key,
488         gboolean retval)
489 {
490     const gchar *str_value = NULL;
491     gint value = 0;
492     g_return_val_if_fail (self && TLM_IS_CONFIG (self), retval);
493
494     str_value = tlm_config_get_string (self, group, key);
495     if (!str_value)
496         return retval;
497
498     if (g_ascii_strncasecmp (str_value, "false", 5) == 0 ||
499         g_ascii_strncasecmp (str_value, "no", 2) == 0)
500         return FALSE;
501
502     if (g_ascii_strncasecmp (str_value, "true", 4) == 0 ||
503         g_ascii_strncasecmp (str_value, "yes", 3) == 0)
504         return TRUE;
505
506     if (sscanf (str_value, "%d", &value) <= 0)
507         return retval;
508
509     return (gboolean) value;
510 }
511
512 /**
513  * tlm_config_set_boolean:
514  * @self: (transfer none): an instance of #TlmConfig
515  * @group: the group name
516  * @key: the key name
517  * @value: the value
518  *
519  * Sets the configuration value to the provided #value.
520  */
521 void
522 tlm_config_set_boolean (
523         TlmConfig *self,
524         const gchar *group,
525         const gchar *key,
526         gboolean value)
527 {
528     g_return_if_fail (self && TLM_IS_CONFIG (self));
529
530     tlm_config_set_int (self, group, key, (gint)value);
531 }
532 /**
533  * tlm_config_has_group:
534  * @self: (transfer none): an instance of #TlmConfig
535  * @group: the group name
536  *
537  * Checks if any configuration available for #group.
538  *
539  * Returns: TRUE if found, FALSE otherwise.
540  */
541 gboolean
542 tlm_config_has_group (
543     TlmConfig *self,
544     const gchar *group)
545 {
546     g_return_val_if_fail (self && TLM_IS_CONFIG (self), FALSE);
547     g_return_val_if_fail (group, FALSE);
548
549     return g_hash_table_contains (self->priv->config_table,
550                                   (gconstpointer)group);
551 }
552
553 /**
554  * tlm_config_has_key:
555  * @self: (transfer none): an instance of #TlmConfig
556  * @group: the group name
557  * @key: the key name
558  *
559  * Checks if #key is in given #group.
560  *
561  * Returns: TRUE, if found, FALSE otherwise.
562  */
563
564 gboolean
565 tlm_config_has_key (
566     TlmConfig *self,
567     const gchar *group,
568     const gchar *key)
569 {
570     GHashTable *group_table = NULL;
571     g_return_val_if_fail (self && TLM_IS_CONFIG (self), FALSE);
572     g_return_val_if_fail (key, FALSE);
573
574     if (!group) group = TLM_CONFIG_GENERAL;
575
576     group_table = tlm_config_get_group (self, group);
577     if (!group_table) return FALSE;
578
579     return g_hash_table_contains (group_table, (gconstpointer)key);
580 }
581
582 static void
583 _cleanup (TlmConfig *self)
584 {
585     if (self->priv->config_table) {
586         g_hash_table_unref (self->priv->config_table);
587         self->priv->config_table = NULL;
588     }
589
590     if (self->priv->config_file_path) {
591         g_free (self->priv->config_file_path);
592         self->priv->config_file_path = NULL;
593     }
594 }
595
596 static void
597 tlm_config_dispose (
598         GObject *object)
599 {
600     TlmConfig *self = 0;
601     g_return_if_fail (object && TLM_IS_CONFIG (object));
602
603     self = TLM_CONFIG (object);
604
605     _cleanup (self);
606
607     G_OBJECT_CLASS (tlm_config_parent_class)->dispose (object);
608 }
609
610 static void
611 tlm_config_finalize (
612         GObject *object)
613 {
614     g_return_if_fail (object && TLM_IS_CONFIG (object));
615
616     G_OBJECT_CLASS (tlm_config_parent_class)->finalize (object);
617 }
618
619 static void
620 tlm_config_class_init (
621         TlmConfigClass *klass)
622 {
623     GObjectClass *object_class = G_OBJECT_CLASS (klass);
624
625     g_type_class_add_private (object_class, sizeof (TlmConfigPrivate));
626
627     object_class->dispose = tlm_config_dispose;
628     object_class->finalize = tlm_config_finalize;
629 }
630
631 static void
632 _initialize (TlmConfig *self)
633 {
634     self->priv->config_file_path = NULL;
635     self->priv->config_table = g_hash_table_new_full (
636                                     g_str_hash,
637                                     g_str_equal,
638                                     g_free,
639                                     (GDestroyNotify)g_hash_table_unref);
640
641
642     if (!_load_config (self))
643         WARN ("load configuration failed, using default settings");
644
645 #ifdef ENABLE_DEBUG
646     _load_environment (self);
647 #endif
648     _set_defaults (self);
649 }
650
651 static void
652 tlm_config_init (
653         TlmConfig *self)
654 {
655     self->priv = TLM_CONFIG_PRIV (self);
656     _initialize (self);
657 }
658
659 /**
660  * tlm_config_reload:
661  * @self: (transfer none): an instance of #TlmConfig
662  *
663  * Reloads the configuration.
664  *
665  */
666 void
667 tlm_config_reload (
668         TlmConfig *self)
669 {
670     g_return_if_fail (self && TLM_IS_CONFIG (self));
671
672     DBG ("reload configuration");
673     _cleanup (self);
674     _initialize (self);
675 }
676
677 /**
678  * tlm_config_new:
679  *
680  * Create a #TlmConfig object.
681  *
682  * Returns: an instance of #TlmConfig.
683  */
684 TlmConfig *
685 tlm_config_new ()
686 {
687     return TLM_CONFIG (g_object_new (TLM_TYPE_CONFIG, NULL));
688 }
689