Release 0.0.2
[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 gchar *
106 _check_config_file (const gchar *path)
107 {
108     gchar *fn = g_build_filename (path, "tlm.conf",   NULL);
109     DBG ("check config at %s", fn);
110     if (g_access (fn, R_OK) == 0)
111         return fn;
112     g_free (fn);
113     return NULL;
114 }
115
116 static gboolean
117 _load_config (TlmConfig *self)
118 {
119     TlmConfigPrivate *priv = self->priv;
120     GError *err = NULL;
121     gchar **groups = NULL;
122     gsize n_groups = 0;
123     int i,j;
124     GKeyFile *settings = g_key_file_new ();
125
126     const gchar * const *sysconfdirs;
127
128     if (!priv->config_file_path) {
129         const gchar *cfg_env = g_getenv ("TLM_CONF_FILE");
130         if (cfg_env) {
131             if (g_access (cfg_env, R_OK) == 0)
132                 priv->config_file_path = g_strdup (cfg_env);
133         }
134     }
135     if (!priv->config_file_path) {
136         priv->config_file_path = _check_config_file (TLM_SYSCONF_DIR);
137     }
138     if (!priv->config_file_path) {
139         sysconfdirs = g_get_system_config_dirs ();
140         while (*sysconfdirs != NULL) {
141             gchar *sys_cfg = _check_config_file (*sysconfdirs);
142             if (sys_cfg) {
143                 priv->config_file_path = sys_cfg;
144                 break;
145             }
146             sysconfdirs++;
147         }
148     }
149
150     if (priv->config_file_path) {
151         DBG ("loading TLM config from %s", priv->config_file_path);
152         if (!g_key_file_load_from_file (settings,
153                                         priv->config_file_path,
154                                         G_KEY_FILE_NONE, &err)) {
155             WARN ("error reading config file at '%s': %s",
156                  priv->config_file_path, err->message);
157             g_error_free (err);
158             g_key_file_free (settings);
159             return FALSE;
160         }
161     }
162     else {
163         WARN ("No valid configuration file found");
164         return FALSE;
165     }
166
167     groups = g_key_file_get_groups (settings, &n_groups);
168
169     for (i = 0; i < n_groups; i++) {
170         GError *err = NULL;
171         gsize n_keys =0;
172         GHashTable *group_table = NULL;
173         gchar **keys = g_key_file_get_keys (settings,
174                                             groups[i],
175                                             &n_keys,
176                                             &err);
177         if (err) {
178             WARN ("fail to read group '%s': %s", groups[i], err->message);
179             g_error_free (err);
180             continue;
181         }
182
183         group_table = (GHashTable *) g_hash_table_lookup (
184                                 priv->config_table, groups[i]);
185         if (!group_table) 
186             group_table = g_hash_table_new_full (
187                                g_str_hash,
188                                g_str_equal,
189                                g_free,
190                                (GDestroyNotify)g_free);
191
192         for (j = 0; j < n_keys; j++) {
193             gchar *value = g_key_file_get_value (settings,
194                                                  groups[i],
195                                                  keys[j],
196                                                  &err);
197             if (err) {
198                 WARN ("fail to read key '%s/%s': %s", groups[i], keys[j],
199                         err->message);
200                 g_error_free (err);
201                 continue;
202             }
203
204             DBG ("found config : '%s/%s' - '%s'", groups[i], keys[j], value);
205
206             g_hash_table_insert (group_table,
207                                  (gpointer)g_strdup (keys[j]),
208                                  (gpointer)value);
209
210         }
211
212         g_hash_table_insert (priv->config_table,
213                              g_strdup (groups[i]),
214                              group_table);
215
216         g_strfreev (keys);
217     }
218
219     g_strfreev (groups);
220
221     g_key_file_free (settings);
222
223     return TRUE;
224 }
225
226 #ifdef ENABLE_DEBUG
227 static void
228 _load_environment (
229         TlmConfig *self)
230 {
231     const gchar *e_val = 0;
232     
233     e_val = g_getenv("TLM_ACCOUNT_PLUGIN");
234     if (e_val)
235         tlm_config_set_string (self, 
236                                TLM_CONFIG_GENERAL, 
237                                TLM_CONFIG_GENERAL_ACCOUNTS_PLUGIN, e_val);
238 }
239 #endif  /* ENABLE_DEBUG */
240
241 static void
242 _set_defaults (
243         TlmConfig *self)
244 {
245
246     /* accounts plugin => default */
247     if (!tlm_config_has_key (self,
248                              TLM_CONFIG_GENERAL,
249                              TLM_CONFIG_GENERAL_ACCOUNTS_PLUGIN)) {
250         tlm_config_set_string (self,
251                                TLM_CONFIG_GENERAL,
252                                TLM_CONFIG_GENERAL_ACCOUNTS_PLUGIN,
253                                "default");
254     }
255
256     /* default PAM service => tlm-login */
257     if (!tlm_config_has_key (self,
258                              TLM_CONFIG_GENERAL,
259                              TLM_CONFIG_GENERAL_PAM_SERVICE)) {
260         tlm_config_set_string (self,
261                                TLM_CONFIG_GENERAL,
262                                TLM_CONFIG_GENERAL_PAM_SERVICE,
263                                "tlm-login");
264     }
265
266     /* default user => guest */
267     if (!tlm_config_has_key (self,
268                              TLM_CONFIG_GENERAL,
269                              TLM_CONFIG_GENERAL_DEFAULT_USER)) {
270         tlm_config_set_string (self,
271                                TLM_CONFIG_GENERAL,
272                                TLM_CONFIG_GENERAL_DEFAULT_USER,
273                                "guest");
274     }
275 }
276
277 /**
278  * tlm_config_get_group:
279  * @self: (transfer none): an instance of #TlmConfig
280  * @group: the group name
281  *
282  * Retrives the configuration in given #group as #GHashTable
283  *
284  * Returns: (transfer none): the key, value paired dictionary if found,
285  * NULL otherwise.
286  */
287 GHashTable *
288 tlm_config_get_group (
289         TlmConfig *self,
290         const gchar *group)
291 {
292     g_return_val_if_fail (self && TLM_IS_CONFIG(self), NULL);
293     g_return_val_if_fail (group && group[0], NULL);
294
295     return (GHashTable *) g_hash_table_lookup (self->priv->config_table,
296                                                   group);
297 }
298
299 /**
300  * tlm_config_get_string:
301  * @self: (transfer none): an instance of #TlmConfig
302  * @group: (transfer none): the group name, NULL refers to General
303  * @key: (transfer none): the key name
304  *
305  * Get a string configuration value.
306  *
307  * Returns: the value corresponding to the key as an string. If the
308  * key does not exist or cannot be converted to the integer, NULL is returned.
309  */
310 const gchar *
311 tlm_config_get_string (
312         TlmConfig *self,
313         const gchar *group,
314         const gchar *key)
315 {
316     g_return_val_if_fail (self && TLM_IS_CONFIG (self), NULL);
317     g_return_val_if_fail (key && key[0], NULL);
318
319     GHashTable *group_table = tlm_config_get_group (self, group);
320     if (!group_table) return NULL;
321
322     return (const gchar *) g_hash_table_lookup (group_table, key);
323 }
324
325 /**
326  * tlm_config_set_string:
327  * @self: (transfer none): an instance of #TlmConfig
328  * @group: (transfer none): the group name
329  * @key: (transfer none): the key name
330  * @value: (transfer none): the value
331  *
332  * Sets the configuration value to the provided string.
333  */
334 void
335 tlm_config_set_string (
336         TlmConfig *self,
337         const gchar *group,
338         const gchar *key,
339         const gchar *value)
340 {
341     g_return_if_fail (self && TLM_IS_CONFIG (self));
342     g_return_if_fail (key && key[0]);
343
344     if (!group) group = TLM_CONFIG_GENERAL;
345
346     GHashTable *group_table = tlm_config_get_group (self, group);
347     if (!group_table) {
348         group_table = g_hash_table_new_full (g_str_hash,
349                                              g_str_equal,
350                                              g_free,
351                                              g_free);
352         g_hash_table_insert (self->priv->config_table,
353                              (gpointer)g_strdup (group),
354                              (gpointer)group_table);
355     }
356
357     g_hash_table_insert (group_table,
358                          (gpointer) g_strdup (key),
359                          (gpointer) g_strdup (value));
360
361 }
362 /**
363  * tlm_config_get_int:
364  * @self: (transfer none): an instance of #TlmConfig
365  * @group: the group name
366  * @key: the key name
367  * @retval: value to be returned in case key is not found
368  *
369  * Get an integer configuration value.
370  *
371  * Returns: the value corresponding to the key as an integer. If the key does
372  * not exist or cannot be converted to the integer, retval is returned.
373  */
374 gint
375 tlm_config_get_int (
376         TlmConfig *self,
377         const gchar *group,
378         const gchar *key,
379         gint retval)
380 {
381     const gchar *str_value = tlm_config_get_string (self, group, key);
382     return (gint) (str_value ? atoi (str_value) : retval);
383 }
384
385 /**
386  * tlm_config_set_int:
387  * @self: (transfer none): an instance of #TlmConfig
388  * @group: the group name
389  * @key: the key name
390  * @value: the value
391  *
392  * Sets the configuration value to the provided integer.
393  */
394 void
395 tlm_config_set_int (
396         TlmConfig *self,
397         const gchar *group,
398         const gchar *key,
399         gint value)
400 {
401     gchar *s_value = 0;
402     g_return_if_fail (self && TLM_IS_CONFIG (self));
403
404     s_value = g_strdup_printf ("%d", value);
405     if (!s_value) return;
406
407     tlm_config_set_string (self, group, key, s_value);
408
409     g_free (s_value);
410 }
411
412 /**
413  * tlm_config_get_uint:
414  * @self: (transfer none): an instance of #TlmConfig
415  * @group: (transfer none): the group name
416  * @key: (transfer none): the key name
417  * @retval: value to be returned in case key is not found
418  *
419  * Get an unsigned integer configuration value.
420  *
421  * Returns: the value corresponding to the key as an unsigned integer. If the
422  * key does not exist or cannot be converted to the integer, retval is returned.
423  */
424 guint
425 tlm_config_get_uint (
426         TlmConfig *self,
427         const gchar *group,
428         const gchar *key,
429         guint retval)
430 {
431     guint value;
432     const gchar *str_value = tlm_config_get_string (self, group, key);
433     if (!str_value || sscanf (str_value, "%u", &value) <= 0) value = retval;
434
435     return value;
436 }
437
438 /**
439  * tlm_config_set_uint:
440  * @self: (transfer none): an instance of #TlmConfig
441  * @group: (transfer none):  the group name
442  * @key: the key name
443  * @value: the value
444  *
445  * Sets the configuration value to the provided unsigned integer.
446  */
447 void
448 tlm_config_set_uint (
449         TlmConfig *self,
450         const gchar *group,
451         const gchar *key,
452         guint value)
453 {
454     gchar *s_value = 0;
455     g_return_if_fail (self && TLM_IS_CONFIG (self));
456
457     s_value = g_strdup_printf ("%u", value);
458     if (!s_value) return;
459
460     tlm_config_set_string (self, group, key, s_value);
461     g_free (s_value);
462 }
463
464 /**
465  * tlm_config_get_boolean:
466  * @self: (transfer none): an instance of #TlmConfig
467  * @group: (transfer none): the group name
468  * @key: (transfer none): the key name
469  * @retval: value to be returned in case key is not found
470  *
471  * Get a boolean configuration value.
472  *
473  * Returns: the value corresponding to the key as boolean. If the
474  * key does not exist or cannot be converted to boolean, retval is returned.
475  */
476 gboolean
477 tlm_config_get_boolean (
478         TlmConfig *self,
479         const gchar *group,
480         const gchar *key,
481         gboolean retval)
482 {
483     const gchar *str_value = NULL;
484     gint value = 0;
485     g_return_val_if_fail (self && TLM_IS_CONFIG (self), retval);
486
487     str_value = tlm_config_get_string (self, group, key);
488     if (!str_value)
489         return retval;
490
491     if (g_ascii_strncasecmp (str_value, "false", 5) == 0 ||
492         g_ascii_strncasecmp (str_value, "no", 2) == 0)
493         return FALSE;
494
495     if (g_ascii_strncasecmp (str_value, "true", 4) == 0 ||
496         g_ascii_strncasecmp (str_value, "yes", 3) == 0)
497         return TRUE;
498
499     if (sscanf (str_value, "%d", &value) <= 0)
500         return retval;
501
502     return (gboolean) value;
503 }
504
505 /**
506  * tlm_config_set_boolean:
507  * @self: (transfer none): an instance of #TlmConfig
508  * @group: the group name
509  * @key: the key name
510  * @value: the value
511  *
512  * Sets the configuration value to the provided #value.
513  */
514 void
515 tlm_config_set_boolean (
516         TlmConfig *self,
517         const gchar *group,
518         const gchar *key,
519         gboolean value)
520 {
521     g_return_if_fail (self && TLM_IS_CONFIG (self));
522
523     tlm_config_set_int (self, group, key, (gint)value);
524 }
525 /**
526  * tlm_config_has_group:
527  * @self: (transfer none): an instance of #TlmConfig
528  * @group: the group name
529  *
530  * Checks if any configuration available for #group.
531  *
532  * Returns: TRUE if found, FALSE otherwise.
533  */
534 gboolean
535 tlm_config_has_group (
536     TlmConfig *self,
537     const gchar *group)
538 {
539     g_return_val_if_fail (self && TLM_IS_CONFIG (self), FALSE);
540     g_return_val_if_fail (group, FALSE);
541
542     return g_hash_table_contains (self->priv->config_table,
543                                   (gconstpointer)group);
544 }
545
546 /**
547  * tlm_config_has_key:
548  * @self: (transfer none): an instance of #TlmConfig
549  * @group: the group name
550  * @key: the key name
551  *
552  * Checks if #key is in given #group.
553  *
554  * Returns: TRUE, if found, FALSE otherwise.
555  */
556
557 gboolean
558 tlm_config_has_key (
559     TlmConfig *self,
560     const gchar *group,
561     const gchar *key)
562 {
563     GHashTable *group_table = NULL;
564     g_return_val_if_fail (self && TLM_IS_CONFIG (self), FALSE);
565     g_return_val_if_fail (key, FALSE);
566
567     if (!group) group = TLM_CONFIG_GENERAL;
568
569     group_table = tlm_config_get_group (self, group);
570     if (!group_table) return FALSE;
571
572     return g_hash_table_contains (group_table, (gconstpointer)key);
573 }
574
575 static void
576 _cleanup (TlmConfig *self)
577 {
578     if (self->priv->config_table) {
579         g_hash_table_unref (self->priv->config_table);
580         self->priv->config_table = NULL;
581     }
582
583     if (self->priv->config_file_path) {
584         g_free (self->priv->config_file_path);
585         self->priv->config_file_path = NULL;
586     }
587 }
588
589 static void
590 tlm_config_dispose (
591         GObject *object)
592 {
593     TlmConfig *self = 0;
594     g_return_if_fail (object && TLM_IS_CONFIG (object));
595
596     self = TLM_CONFIG (object);
597
598     _cleanup (self);
599
600     G_OBJECT_CLASS (tlm_config_parent_class)->dispose (object);
601 }
602
603 static void
604 tlm_config_finalize (
605         GObject *object)
606 {
607     g_return_if_fail (object && TLM_IS_CONFIG (object));
608
609     G_OBJECT_CLASS (tlm_config_parent_class)->finalize (object);
610 }
611
612 static void
613 tlm_config_class_init (
614         TlmConfigClass *klass)
615 {
616     GObjectClass *object_class = G_OBJECT_CLASS (klass);
617
618     g_type_class_add_private (object_class, sizeof (TlmConfigPrivate));
619
620     object_class->dispose = tlm_config_dispose;
621     object_class->finalize = tlm_config_finalize;
622 }
623
624 static void
625 _initialize (TlmConfig *self)
626 {
627     self->priv->config_file_path = NULL;
628     self->priv->config_table = g_hash_table_new_full (
629                                     g_str_hash,
630                                     g_str_equal,
631                                     g_free,
632                                     (GDestroyNotify)g_hash_table_unref);
633
634
635     if (!_load_config (self))
636         WARN ("load configuration failed, using default settings");
637
638 #ifdef ENABLE_DEBUG
639     _load_environment (self);
640 #endif
641     _set_defaults (self);
642 }
643
644 static void
645 tlm_config_init (
646         TlmConfig *self)
647 {
648     self->priv = TLM_CONFIG_PRIV (self);
649     _initialize (self);
650 }
651
652 /**
653  * tlm_config_reload:
654  * @self: (transfer none): an instance of #TlmConfig
655  *
656  * Reloads the configuration.
657  *
658  */
659 void
660 tlm_config_reload (
661         TlmConfig *self)
662 {
663     g_return_if_fail (self && TLM_IS_CONFIG (self));
664
665     DBG ("reload configuration");
666     _cleanup (self);
667     _initialize (self);
668 }
669
670 /**
671  * tlm_config_new:
672  *
673  * Create a #TlmConfig object.
674  *
675  * Returns: an instance of #TlmConfig.
676  */
677 TlmConfig *
678 tlm_config_new ()
679 {
680     return TLM_CONFIG (g_object_new (TLM_TYPE_CONFIG, NULL));
681 }
682