tizen 2.3 release
[external/buxton.git] / src / shared / configurator.c
1 /*
2  * This file is part of buxton.
3  *
4  * Copyright (C) 2013 Intel Corporation
5  *
6  * buxton is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1
9  * of the License, or (at your option) any later version.
10  */
11
12 #ifdef HAVE_CONFIG_H
13         #include "config.h"
14 #endif
15
16 #include <assert.h>
17 #include <iniparser.h>
18 #include <linux/limits.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "configurator.h"
25 #include "log.h"
26
27 /**
28  * Section name in ini file for our configuration
29  */
30 #define CONFIG_SECTION "Configuration"
31
32 #ifndef HAVE_SECURE_GETENV
33 #  ifdef HAVE___SECURE_GETENV
34 #    define secure_getenv __secure_getenv
35 #  else
36 #    error neither secure_getenv nor __secure_getenv is available
37 #  endif
38 #endif
39
40 /**
41  * @internal
42  * internal state of configurator
43  */
44 static struct _conf {
45         bool initialized;       /**< track if it's been init'd */
46         char* keys[CONFIG_MAX]; /**< bag of values */
47         dictionary* ini;        /**< ini parser dictionary */
48 } conf = {
49         .initialized = false,
50         .keys = {0},
51         .ini = NULL
52 };
53
54 /**
55  * @internal
56  * config keys as in environment
57  * @fixme name sucks
58  */
59 static const char *KS[CONFIG_MAX] = {
60         NULL,
61         "BUXTON_CONF_FILE",
62         "BUXTON_MODULE_DIR",
63         "BUXTON_DB_PATH",
64         "BUXTON_SMACK_LOAD_FILE",
65         "BUXTON_BUXTON_SOCKET"
66 };
67
68 /**
69  * @internal
70  * keys as they are used in config file
71  */
72 static const char *config_keys[CONFIG_MAX] = {
73         NULL,
74         NULL,                   /**< conf file entry in config file is meaningless */
75         "ModuleDirectory",
76         "DatabasePath",
77         "SmackLoadFile",
78         "SocketPath"
79 };
80
81 static const char *COMPILE_DEFAULT[CONFIG_MAX] = {
82         NULL,
83         _DEFAULT_CONFIGURATION_FILE,
84         _MODULE_DIRECTORY,
85         _DB_PATH,
86         _SMACK_LOAD_FILE,
87         _BUXTON_SOCKET
88 };
89
90 /**
91  * @internal
92  * wrap strdup and die if malloc fails
93  *
94  * @note This may seem lame and stupid at first glance. The former is
95  * right the latter is not. This function may abort()
96  *
97  * @return pointer to dup'd string
98  */
99 __attribute__ ((pure))
100 static inline char *_strdup(const char* string)
101 {
102         char* s;
103
104         s = strdup(string);
105         if (s == NULL) {
106                 abort();
107         }
108         return s;
109 }
110
111 /**
112  * @internal
113  * grab a string from the ini file
114  *
115  * @param section the section of the ini file
116  * @param name the name of the key
117  * @param required if key required or not
118  * @param def default value for nonrequired setting
119  *
120  * @note This function may abort()
121  *
122  * @return The value as a string. The the string is internal to
123  * libini, and if at this stage of the game it is null, just die.
124  * Something is really wrong and even if we could recover, the system
125  * is not working correctly.
126  */
127 static char *get_ini_string(char *section, char *name, bool required,
128         char *def)
129 {
130         char buf[PATH_MAX];
131         char *s;
132
133         assert(conf.ini);
134         snprintf(buf, sizeof(buf), "%s:%s", section, name);
135         s = iniparser_getstring(conf.ini, buf, def);
136         if (s == NULL && required) {
137                 abort();
138         }
139         return s;
140 }
141
142 /**
143  * analagous method to get_ini_string()
144  *
145  * @param section the section of the ini file
146  * @param name the name of the key
147  * @param required if key required or not
148  * @param def default value for nonrequired setting
149  *
150  * @note inlined b/c only used once and why not.
151  *
152  * @return the value
153  */
154 static inline int get_ini_int(char *section, char *name, bool required,
155         int def)
156 {
157         char buf[PATH_MAX];
158         int exists;
159
160         assert(conf.ini);
161         snprintf(buf, sizeof(buf), "%s:%s", section, name);
162         exists = iniparser_find_entry(conf.ini, buf);
163         if (!exists && required) {
164                 abort();
165         }
166         return iniparser_getint(conf.ini, buf, def);
167 }
168
169 /**
170  * @internal
171  * Initialize conf
172  *
173  */
174 static void initialize(void)
175 {
176         if (conf.initialized) {
177                 return;
178         }
179
180         for (int i= CONFIG_MIN+1; i < CONFIG_MAX; i++) {
181                 char *envkey;
182
183                 /* hasn't been set through command line */
184                 if (conf.keys[i] == NULL) {
185                         /* second priority is env */
186                         envkey = secure_getenv(KS[i]);
187                         if (envkey) {
188                                 conf.keys[i] = _strdup(envkey);
189                         }
190                 }
191
192                 /* third priority is conf file */
193                 if (conf.keys[i] == NULL && conf.ini) {
194                         /* for once config file is loaded */
195                         char key[PATH_MAX+strlen(CONFIG_SECTION)+1+1]; /* one for null and one for : */
196                         char *value;
197
198                         snprintf(key, sizeof(key), "%s:%s", CONFIG_SECTION, config_keys[i]);
199                         value = iniparser_getstring(conf.ini, key, NULL);
200                         if (value != NULL) {
201                                 conf.keys[i] = _strdup(value);
202                         }
203                 }
204
205                 if (conf.keys[i] == NULL) {
206                         /* last priority is compile time defaults */
207                         conf.keys[i] = _strdup(COMPILE_DEFAULT[i]);
208                 }
209
210                 /* if config file is not loaded, load */
211                 if (i == CONFIG_CONF_FILE) {
212                         char *path = conf.keys[CONFIG_CONF_FILE];
213
214                         conf.ini = iniparser_load(path);
215                         if (conf.ini == NULL) {
216                                 buxton_log("Failed to load buxton conf file: %s\n", path);
217                         }
218                 }
219         }
220         conf.initialized = true;
221 }
222
223 /**
224  * @internal
225  * use a destructor to free everything rather than yucky at_exit
226  * nonsense
227  *
228  * @return
229  */
230 __attribute__ ((destructor)) static void free_conf(void)
231 {
232         if (!conf.initialized) {
233                 return;
234         }
235         for (int i= CONFIG_MIN+1; i < CONFIG_MAX; i++) {
236                 free(conf.keys[i]);
237         }
238         iniparser_freedict(conf.ini);
239 }
240
241 void buxton_add_cmd_line(ConfigKey confkey, char* data)
242 {
243         if (confkey >= CONFIG_MAX || confkey <= CONFIG_MIN) {
244                 buxton_log("invalid confkey");
245                 return;
246         }
247         if (!data) {
248                 buxton_log("invalid data");
249                 return;
250         }
251
252         conf.keys[confkey] = _strdup(data);
253 }
254
255 const char* buxton_module_dir(void)
256 {
257         initialize();
258         return (const char*)conf.keys[CONFIG_MODULE_DIR];
259 }
260
261 const char* buxton_conf_file(void)
262 {
263         initialize();
264         return (const char*)conf.keys[CONFIG_CONF_FILE];
265 }
266
267 const char* buxton_db_path(void)
268 {
269         initialize();
270         return (const char*)conf.keys[CONFIG_DB_PATH];
271 }
272
273 const char* buxton_smack_load_file(void)
274 {
275         initialize();
276         return (const char*)conf.keys[CONFIG_SMACK_LOAD_FILE];
277 }
278
279 const char* buxton_socket(void)
280 {
281         initialize();
282         return (const char*)conf.keys[CONFIG_BUXTON_SOCKET];
283 }
284
285 int buxton_key_get_layers(ConfigLayer **layers)
286 {
287         ConfigLayer *_layers;
288         int n;
289         int j = 0;
290
291         assert(layers);
292         initialize();
293         if (conf.ini == NULL) {
294                 buxton_log("config file not loaded when calling buxton_key_get_layers()");
295                 abort();
296         }
297         n = iniparser_getnsec(conf.ini);
298         _layers = (ConfigLayer*)calloc((size_t)n, sizeof(ConfigLayer));
299         if (_layers == NULL) {
300                 abort();
301         }
302         for (int i= 0; i < n; i++) {
303                 char *section_name;
304
305                 section_name = iniparser_getsecname(conf.ini, i);
306                 if (!section_name) {
307                         abort();
308                 }
309                 if (!strcasecmp(section_name, CONFIG_SECTION)) {
310                         continue;
311                 }
312                 _layers[j].name = section_name;
313                 _layers[j].description = get_ini_string(section_name,
314                         "Description", true, NULL);
315                 _layers[j].backend = get_ini_string(section_name, "Backend",
316                         true, NULL);
317                 _layers[j].type = get_ini_string(section_name, "Type", true,
318                         NULL);
319                 _layers[j].priority = get_ini_int(section_name, "Priority",
320                         true, 0);
321                 _layers[j].access = get_ini_string(section_name, "Access",
322                         false, "read-write");
323                 j++;
324         }
325         *layers = _layers;
326         return j;
327 }
328
329 void include_configurator(void)
330 {
331         ;
332 }
333
334
335 /*
336  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
337  *
338  * Local variables:
339  * c-basic-offset: 8
340  * tab-width: 8
341  * indent-tabs-mode: t
342  * End:
343  *
344  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
345  * :indentSize=8:tabSize=8:noTabs=false:
346  */