tizen 2.3 release
[external/buxton.git] / src / shared / backend.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 <dlfcn.h>
17
18 #include "configurator.h"
19 #include "backend.h"
20 #include "hashmap.h"
21 #include "util.h"
22 #include "log.h"
23 #include "buxtonarray.h"
24 #include "smack.h"
25
26 /**
27  * Create a BuxtonLayer out of a ConfigLayer
28  *
29  * Validates the data from the config file and creates BuxtonLayer.
30  *
31  * @param conf_layer the ConfigLayer to validate
32  *
33  * @return a new BuxtonLayer.  Callers are responsible for managing
34  * this memory
35  */
36 static BuxtonLayer *buxton_layer_new(ConfigLayer *conf_layer);
37
38 /* Load layer configurations from disk */
39 void buxton_init_layers(BuxtonConfig *config)
40 {
41         Hashmap *layers = NULL;
42         int nlayers = 0;
43         ConfigLayer *config_layers = NULL;
44         int r;
45
46         nlayers = buxton_key_get_layers(&config_layers);
47         layers = hashmap_new(string_hash_func, string_compare_func);
48         if (!layers) {
49                 abort();
50         }
51
52         for (int n = 0; n < nlayers; n++) {
53                 BuxtonLayer *layer;
54
55                 layer = buxton_layer_new(&(config_layers[n]));
56                 if (!layer) {
57                         abort();
58                 }
59
60                 r = hashmap_put(layers, layer->name.value, layer);
61                 if (r != 1) {
62                         abort();
63                 }
64         }
65
66         config->layers = layers;
67         free(config_layers);
68 }
69
70 static bool is_read_only(ConfigLayer *conf_layer)
71 {
72         return strcmp(conf_layer->access, "read-only") == 0;
73 }
74
75 static BuxtonLayer *buxton_layer_new(ConfigLayer *conf_layer)
76 {
77         BuxtonLayer *out;
78
79         assert(conf_layer);
80         out= malloc0(sizeof(BuxtonLayer));
81         if (!out) {
82                 abort();
83         }
84
85         if (conf_layer->priority < 0) {
86                 goto fail;
87         }
88         out->name.value = strdup(conf_layer->name);
89         if (!out->name.value) {
90                 abort();
91         }
92         out->name.length = (uint32_t)strlen(conf_layer->name);
93
94         if (strcmp(conf_layer->type, "System") == 0) {
95                 out->type = LAYER_SYSTEM;
96         } else if (strcmp(conf_layer->type, "User") == 0) {
97                 out->type = LAYER_USER;
98         } else {
99                 buxton_log("Layer %s has unknown type: %s\n", conf_layer->name, conf_layer->type);
100                 goto fail;
101         }
102
103         if (strcmp(conf_layer->backend, "gdbm") == 0) {
104                 out->backend = BACKEND_GDBM;
105         } else if (strcmp(conf_layer->backend, "memory") == 0) {
106                 out->backend = BACKEND_MEMORY;
107         } else {
108                 buxton_log("Layer %s has unknown database: %s\n", conf_layer->name, conf_layer->backend);
109                 goto fail;
110         }
111
112         if (conf_layer->description != NULL) {
113                 out->description = strdup(conf_layer->description);
114                 if (!out->description) {
115                         abort();
116                 }
117         }
118
119         out->readonly = is_read_only(conf_layer);
120         out->priority = conf_layer->priority;
121         return out;
122 fail:
123         free(out->name.value);
124         free(out->description);
125         free(out);
126         return NULL;
127 }
128
129 static void init_backend(BuxtonConfig *config,
130                          BuxtonLayer *layer,
131                          BuxtonBackend **backend)
132 {
133         void *handle, *cast;
134         _cleanup_free_ char *path = NULL;
135         const char *name;
136         char *error;
137         int r;
138         bool rb;
139         module_init_func i_func;
140         module_destroy_func d_func;
141         BuxtonBackend *backend_tmp;
142
143         assert(layer);
144         assert(backend);
145
146         if (layer->backend == BACKEND_GDBM) {
147                 name = "gdbm";
148         } else if (layer->backend == BACKEND_MEMORY) {
149                 name = "memory";
150         } else {
151                 buxton_log("Invalid backend type for layer: %s\n", layer->name);
152                 abort();
153         }
154
155         backend_tmp = hashmap_get(config->backends, name);
156
157         if (backend_tmp) {
158                 *backend = backend_tmp;
159                 return;
160         }
161
162         backend_tmp = malloc0(sizeof(BuxtonBackend));
163         if (!backend_tmp) {
164                 abort();
165         }
166
167         r = asprintf(&path, "%s/%s.so", buxton_module_dir(), name);
168         if (r == -1) {
169                 abort();
170         }
171
172         /* Load the module */
173         handle = dlopen(path, RTLD_LAZY);
174
175         if (!handle) {
176                 buxton_log("dlopen(): %s\n", dlerror());
177                 abort();
178         }
179
180         dlerror();
181         cast = dlsym(handle, "buxton_module_init");
182         if ((error = dlerror()) != NULL || !cast) {
183                 buxton_log("dlsym(): %s\n", error);
184                 abort();
185         }
186         memcpy(&i_func, &cast, sizeof(i_func));
187         dlerror();
188
189         cast = dlsym(handle, "buxton_module_destroy");
190         if ((error = dlerror()) != NULL || !cast) {
191                 buxton_log("dlsym(): %s\n", error);
192                 abort();
193         }
194         memcpy(&d_func, &cast, sizeof(d_func));
195
196         rb = i_func(backend_tmp);
197         if (!rb) {
198                 buxton_log("buxton_module_init failed\n");
199                 abort();
200         }
201
202         if (!config->backends) {
203                 config->backends = hashmap_new(trivial_hash_func, trivial_compare_func);
204                 if (!config->backends) {
205                         abort();
206                 }
207         }
208
209         r = hashmap_put(config->backends, name, backend_tmp);
210         if (r != 1) {
211                 abort();
212         }
213
214         backend_tmp->module = handle;
215         backend_tmp->destroy = d_func;
216
217         *backend = backend_tmp;
218 }
219
220 BuxtonBackend *backend_for_layer(BuxtonConfig *config,
221                                  BuxtonLayer *layer)
222 {
223         BuxtonBackend *backend;
224         int ret;
225
226         assert(layer);
227
228         if (!config->databases) {
229                 config->databases = hashmap_new(string_hash_func, string_compare_func);
230                 if (!config->databases) {
231                         abort();
232                 }
233         }
234         if ((backend = (BuxtonBackend*)hashmap_get(config->databases, layer->name.value)) == NULL) {
235                 /* attempt load of backend */
236                 init_backend(config, layer, &backend);
237
238                 ret = hashmap_put(config->databases, layer->name.value, backend);
239                 if (ret != 1) {
240                         abort();
241                 }
242         }
243         return (BuxtonBackend*)hashmap_get(config->databases, layer->name.value);
244 }
245
246 void destroy_backend(BuxtonBackend *backend)
247 {
248
249         assert(backend);
250
251         backend->set_value = NULL;
252         backend->get_value = NULL;
253         backend->list_keys = NULL;
254         backend->unset_value = NULL;
255         backend->destroy();
256         dlclose(backend->module);
257         free(backend);
258         backend = NULL;
259 }
260
261 /*
262  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
263  *
264  * Local variables:
265  * c-basic-offset: 8
266  * tab-width: 8
267  * indent-tabs-mode: t
268  * End:
269  *
270  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
271  * :indentSize=8:tabSize=8:noTabs=false:
272  */