database: remove duplited lines
[apps/agl-service-data-persistence.git] / ll-database-binding / src / ll-database-binding.c
1 /*
2  * Copyright 2017 IoT.bzh
3  *
4  * author: Loïc Collignon <loic.collignon@iot.bzh>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #define _GNU_SOURCE
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <pwd.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <linux/limits.h>
26 #include <json-c/json.h>
27 #include <db.h>
28
29 #define AFB_BINDING_VERSION 2
30 #include <afb/afb-binding.h>
31
32 #include "utils.h"
33
34 #ifndef MAX_PATH
35 #define MAX_PATH 1024
36 #endif
37
38 #define DBFILE          "/ll-database-binding.db"
39 #define USERNAME        "agl"
40 #define APPNAME         "firefox"
41
42 // ----- Globals -----
43 DB*             database;
44 char    database_file[MAX_PATH];
45
46 // ----- Binding's declarations -----
47 int ll_database_binding_init();
48 void verb_insert(struct afb_req req);
49 void verb_update(struct afb_req req);
50 void verb_delete(struct afb_req req);
51 void verb_read(struct afb_req req);
52
53 // ----- Binding's implementations -----
54
55 /**
56  * @brief Initialize the binding.
57  * @return Exit code, zero if success.
58  */
59 int ll_database_binding_init()
60 {
61         struct passwd pwd;
62         struct passwd* result;
63         char buf[MAX_PATH];
64         size_t bufsize;
65         int ret;
66         
67         bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
68         if (bufsize == -1 || bufsize > MAX_PATH) bufsize = MAX_PATH;
69         
70         ret = getpwuid_r(getuid(), &pwd, buf, bufsize, &result);
71         if (result == NULL)
72         {
73                 if (ret == 0) AFB_ERROR("User not found");
74                 else AFB_ERROR("getpwuid_r failed with %d code", ret);
75                 return ret ? ret : -1;
76         }
77         
78         memset(database_file, 0, MAX_PATH);     
79         strcat(database_file, result->pw_dir);
80         strcat(database_file, DBFILE);
81         
82         AFB_INFO("The database file is '%s'", database_file);
83
84         if ((ret = db_create(&database, NULL, 0)) != 0)
85         {
86                 AFB_ERROR("Failed to create database: %s.", db_strerror(ret));
87                 return 1;
88         }
89         
90         if ((ret = database->open(database, NULL, database_file, NULL, DB_BTREE, DB_CREATE, 0664)) != 0)
91         {
92                 AFB_ERROR("Failed to open the '%s' database: %s.", database_file, db_strerror(ret));
93                 database->close(database, 0);
94                 return 1;
95         }
96         
97         return 0;
98 }
99
100 /**
101  * @brief Handle the @c read verb.
102  * @param[in] req The query.
103  */
104 void verb_insert(struct afb_req req)
105 {
106         DBT key;
107         DBT data;
108         int ret;
109         
110         char* rkey;
111         const char* tag;
112         const char* value;
113         
114         struct json_object* args;
115         struct json_object* item;
116         
117         args = afb_req_json(req);
118         
119         if (!args)
120         {
121                 afb_req_fail(req, "No argument provided.", NULL);
122                 return;
123         }
124         
125         if (!json_object_object_get_ex(args, "key", &item) || !item) tag = NULL;
126         else tag = json_object_get_string(item);
127         
128         if (!tag || !strlen(tag))
129         {
130                 afb_req_fail(req, "No tag provided.", NULL);
131                 return;
132         }
133         
134         if (!json_object_object_get_ex(args, "value", &item) || !item) value = NULL;
135         else value = json_object_get_string(item);
136         
137         if (!value || !strlen(value))
138         {
139                 afb_req_fail(req, "No value provided.", NULL);
140                 return;
141         }
142         
143         rkey = malloc(strlen(USERNAME) + strlen(APPNAME) + strlen(tag) + 3);
144         strcpy(rkey, USERNAME);
145         strcat(rkey, ":");
146         strcat(rkey, APPNAME);
147         strcat(rkey, ":");
148         strcat(rkey, tag);
149         
150         AFB_INFO("insert: key=%s, value=%s", rkey, value);
151
152         memset(&key, 0, sizeof(key));
153         memset(&data, 0, sizeof(data));
154         
155         key.data = rkey;
156         key.size = strlen(rkey);
157         
158         data.data = (void*)value;
159         data.size = strlen(value);
160
161         if ((ret = database->put(database, NULL, &key, &data, DB_NOOVERWRITE)) == 0)
162                 afb_req_success_f(req, NULL, "db success: insertion %s=%s.", (char*)key.data, (char*)data.data);
163         else
164                 afb_req_fail_f(req, "Failed to insert datas.", "db fail: insertion : %s=%s - %s", (char*)key.data, (char*)data.data, db_strerror(ret));
165         free(rkey);
166 }
167
168 void verb_update(struct afb_req req)
169 {
170         DBT key;
171         DBT data;
172         int ret;
173         
174         char* rkey;
175         const char* tag;
176         const char* value;
177         
178         struct json_object* args;
179         struct json_object* item;
180         
181         args = afb_req_json(req);
182         // username should be get from identity binding
183         // application should be get from smack
184         // tag should be get using get_json_string(args, "tag");
185         
186         if (!args)
187         {
188                 afb_req_fail(req, "No argument provided.", NULL);
189                 return;
190         }
191         
192         if (!json_object_object_get_ex(args, "tag", &item) || !item) tag = NULL;
193         else tag = json_object_get_string(item);
194         
195         if (!tag || !strlen(tag))
196         {
197                 afb_req_fail(req, "No tag provided.", NULL);
198                 return;
199         }
200         
201         if (!json_object_object_get_ex(args, "value", &item) || !item) value = NULL;
202         else value = json_object_get_string(item);
203         
204         if (!value || !strlen(value))
205         {
206                 afb_req_fail(req, "No value provided.", NULL);
207                 return;
208         }
209         
210         rkey = malloc(strlen(USERNAME) + strlen(APPNAME) + strlen(tag) + 3);
211         strcpy(rkey, USERNAME);
212         strcat(rkey, ":");
213         strcat(rkey, APPNAME);
214         strcat(rkey, ":");
215         strcat(rkey, tag);
216         
217         AFB_INFO("update: key=%s, value=%s", rkey, value);
218
219         memset(&key, 0, sizeof(key));
220         memset(&data, 0, sizeof(data));
221         
222         key.data = rkey;
223         key.size = strlen(rkey);
224         
225         data.data = (void*)value;
226         data.size = strlen(value);
227
228         if ((ret = database->put(database, NULL, &key, &data, 0)) == 0)
229                 afb_req_success_f(req, NULL, "db success: update %s=%s.", (char*)key.data, (char*)data.data);
230         else
231                 afb_req_fail_f(req, "Failed to update datas.", "db fail: update %s=%s - %s", (char*)key.data, (char*)data.data, db_strerror(ret));
232         free(rkey);
233 }
234
235 void verb_delete(struct afb_req req)
236 {
237         DBT key;
238         int ret;
239         
240         char* rkey;
241         const char* tag;
242         
243         struct json_object* args;
244         struct json_object* item;
245         
246         args = afb_req_json(req);
247         
248         if (!args)
249         {
250                 afb_req_fail(req, "No argument provided.", NULL);
251                 return;
252         }
253         
254         if (!json_object_object_get_ex(args, "tag", &item) || !item) tag = NULL;
255         else tag = json_object_get_string(item);
256         
257         if (!tag || !strlen(tag))
258         {
259                 afb_req_fail(req, "No tag provided.", NULL);
260                 return;
261         }
262         
263         rkey = malloc(strlen(USERNAME) + strlen(APPNAME) + strlen(tag) + 3);
264         strcpy(rkey, USERNAME);
265         strcat(rkey, ":");
266         strcat(rkey, APPNAME);
267         strcat(rkey, ":");
268         strcat(rkey, tag);
269         
270         AFB_INFO("delete: key=%s", rkey);
271
272         memset(&key, 0, sizeof(key));
273         
274         key.data = rkey;
275         key.size = strlen(rkey);
276
277         if ((ret = database->del(database, NULL, &key, 0)) == 0)
278                 afb_req_success_f(req, NULL, "db success: delete %s.", (char *)key.data);
279         else
280                 afb_req_fail_f(req, "Failed to delete datas.", "db fail: delete %s - %s", (char*)key.data, db_strerror(ret));
281         free(rkey);
282 }
283
284 void verb_read(struct afb_req req)
285 {
286         DB* dbp;
287         DBT key;
288         DBT data;
289         int ret;
290         
291         char* rkey;
292         const char* tag;
293         char value[4096];
294         
295         struct json_object* args;
296         struct json_object* item;
297         struct json_object* result;
298         struct json_object* val;
299         
300         args = afb_req_json(req);
301         
302         if (!args)
303         {
304                 afb_req_fail(req, "No argument provided.", NULL);
305                 return;
306         }
307         
308         if (!json_object_object_get_ex(args, "tag", &item) || !item) tag = NULL;
309         else tag = json_object_get_string(item);
310         
311         if (!tag || !strlen(tag))
312         {
313                 afb_req_fail(req, "No tag provided.", NULL);
314                 return;
315         }
316         
317         rkey = malloc(strlen(USERNAME) + strlen(APPNAME) + strlen(tag) + 3);
318         strcpy(rkey, USERNAME);
319         strcat(rkey, ":");
320         strcat(rkey, APPNAME);
321         strcat(rkey, ":");
322         strcat(rkey, tag);
323         
324         AFB_INFO("update: key=%s, value=%s", rkey, value);
325
326         memset(&key, 0, sizeof(key));
327         memset(&data, 0, sizeof(data));
328         memset(&value, 0, 4096);
329         
330         key.data = rkey;
331         key.size = strlen(rkey);
332         
333         data.data = value;
334         data.ulen = 4096;
335         data.flags = DB_DBT_USERMEM;
336
337         if ((ret = database->get(database, NULL, &key, &data, 0)) == 0)
338         {
339                 result = json_object_new_object();
340                 val = json_tokener_parse((char*)data.data);
341                 json_object_object_add(result, "value", val ? val : json_object_new_string((char*)data.data));
342                 
343                 afb_req_success_f(req, result, "db success: read %s=%s.", (char*)key.data, (char*)data.data);
344         }
345         else
346                 afb_req_fail_f(req, "Failed to read datas.", "db fail: read %s - %s", (char*)key.data, db_strerror(ret));
347         free(rkey);
348 }
349
350 // ----- Binding's configuration -----
351 static const struct afb_auth ll_database_binding_auths[] = {
352 };
353
354 static const afb_verb_v2 ll_database_binding_verbs[]= {
355                 REGISTER_VERB(insert,   NULL, NULL, AFB_SESSION_NONE_V2),
356                 REGISTER_VERB(update,   NULL, NULL, AFB_SESSION_NONE_V2),
357                 REGISTER_VERB(delete,   NULL, NULL, AFB_SESSION_NONE_V2),
358                 REGISTER_VERB(read,             NULL, NULL, AFB_SESSION_NONE_V2),
359         { .verb = NULL}
360 };
361
362 const struct afb_binding_v2 afbBindingV2 = {
363                 .api = "ll-database",
364                 .specification = NULL,
365                 .verbs = ll_database_binding_verbs,
366                 .preinit = NULL,
367                 .init = ll_database_binding_init,
368                 .onevent = NULL,
369                 .noconcurrency = 0
370 };