init_db : allocate one more byte to boolean value
[platform/core/api/system-info.git] / src / init_db / system_info_db_init.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <ctype.h>
23 #include <getopt.h>
24 #include <gdbm.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <dlog.h>
28
29 #include <system_info.h>
30 #include <iniparser.h>
31 #include <libxml/xmlmemory.h>
32 #include <libxml/parser.h>
33 #include <libxml/tree.h>
34
35 #include "system_info_private.h"
36
37 #ifdef LOG_TAG
38 #undef LOG_TAG
39 #endif
40
41 #define LOG_TAG "SYSTEM_INFO"
42 #define _D(fmt, args...)   SLOGD(fmt, ##args)
43 #define _E(fmt, args...)   SLOGE(fmt, ##args)
44 #define _I(fmt, args...)   SLOGI(fmt, ##args)
45
46 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
47
48 #define KEY_MAX 256
49
50 #define MODEL_CONFIG_TAG "model-config"
51 #define KEY_PREFIX "http://"
52
53 extern const struct runtime runtime[LANG_MAX];
54
55 static int db_set_value(GDBM_FILE *db, char *tag, char *name, char *type, char *value, int val_len)
56 {
57         char key[KEY_MAX];
58         datum d_key;
59         datum d_data;
60         int ret;
61
62         if (!db || !*db || !tag || !name || !type || !value)
63                 return -EINVAL;
64
65         if (name == strstr(name, KEY_PREFIX))
66                 snprintf(key, sizeof(key), "%s:%s:%s", name, type, tag);
67         else
68                 snprintf(key, sizeof(key), "%s%s:%s:%s", KEY_PREFIX, name, type, tag);
69
70         d_key.dptr = key;
71         d_key.dsize = strlen(key) + 1;
72
73         d_data.dptr = value;
74         d_data.dsize = val_len + 1;
75
76         ret = gdbm_store(*db, d_key, d_data, GDBM_REPLACE);
77         if (ret != 0) {
78                 _E("Failed to store key (%s, %s, %d)", key, type, gdbm_errno);
79                 return -gdbm_errno;
80         }
81
82         gdbm_sync(*db);
83
84         _I("DB: value (key:%s,value:%s) is stored", key, value);
85
86         return 0;
87 }
88
89 static int db_get_value(GDBM_FILE *db, char *tag, char *name, char *type, char *value, int val_len)
90 {
91         datum d_key;
92         datum d_data;
93         char key[KEY_MAX];
94
95         if (!db || !*db || !tag || !name || !type || !value)
96                 return -EINVAL;
97
98         if (name == strstr(name, KEY_PREFIX))
99                 snprintf(key, sizeof(key), "%s:%s:%s", name, type, tag);
100         else
101                 snprintf(key, sizeof(key), "%s%s:%s:%s", KEY_PREFIX, name, type, tag);
102
103         d_key.dptr = key;
104         d_key.dsize = strlen(key) + 1;
105
106         d_data = gdbm_fetch(*db, d_key);
107         if (!d_data.dptr) {
108                 _E("Failed to find key (%s, %s)", key, type);
109                 return -gdbm_errno;
110         }
111
112         snprintf(value, val_len, "%s", d_data.dptr);
113         free(d_data.dptr);
114
115         _I("DB: value (key:%s,value:%s) is fetched", key, value);
116
117         return 0;
118 }
119
120 static int db_set_value_specific_runtime(GDBM_FILE *db, char *tag, char *name, char *type, char *value, int lang)
121 {
122         char value_intg[LANG_MAX + 1] = {0};
123         int ret;
124
125         ret = db_get_value(db, tag, name, type, value_intg, LANG_MAX);
126         if (ret != 0)
127                 return ret;
128
129         value_intg[lang] = (value[0] == 't' ? 'T' : 'F');
130         ret = db_set_value(db, tag, name, type, value_intg, LANG_MAX);
131
132         return ret;
133 }
134
135 static int db_set_value_foreach_runtime(GDBM_FILE *db, xmlNode *node,
136                                                 char *tag, char *name, char *type, char *value)
137 {
138         int rt;
139         xmlChar *prop_val;
140         char value_intg[LANG_MAX + 1] = {0};
141         int ret;
142
143         memset(value_intg, strncmp(value, "true", 4) ? 'F' : 'T', LANG_MAX);
144
145         for (rt = 0; rt < LANG_MAX; rt++) {
146                 if (!runtime[rt].xml_prop)
147                         break;
148
149                 prop_val = xmlGetProp(node, (xmlChar *)(runtime[rt].xml_prop));
150                 if (!prop_val)
151                         continue;
152
153                 value_intg[runtime[rt].lang] = xmlStrcmp(prop_val, (xmlChar *)"on") ? 'F' : 'T';
154
155                 xmlFree(prop_val);
156         }
157
158         ret = db_set_value(db, tag, name, type, value_intg, LANG_MAX);
159
160         return ret;
161 }
162
163 static int system_info_get_values_config_xml(GDBM_FILE *db)
164 {
165         xmlDocPtr doc;
166         xmlNodePtr cur;
167         xmlNode *cur_node, *tag_node;
168         char *tag, *name, *type, *value;
169         int ret;
170
171         if (!db || !*db)
172                 return -EINVAL;
173
174         doc = xmlParseFile(CONFIG_FILE_PATH);
175         if (!doc) {
176                 _E("cannot file open %s file!!!", CONFIG_FILE_PATH);
177                 return SYSTEM_INFO_ERROR_IO_ERROR;
178         }
179
180         cur = xmlDocGetRootElement(doc);
181         if (!cur) {
182                 _E("empty document %s file!!!", CONFIG_FILE_PATH);
183                 ret = -ENOENT;
184                 goto out;
185         }
186
187         for (cur_node = cur; cur_node ; cur_node = cur_node->next) {
188                 if (!xmlStrcmp(cur->name, (const xmlChar*)MODEL_CONFIG_TAG))
189                         break;
190         }
191         if (!cur_node) {
192                 _E("cannot find %s root element file!!!", MODEL_CONFIG_TAG);
193                 ret = -ENOENT;
194                 goto out;
195         }
196
197         cur = cur_node->xmlChildrenNode;
198         for (tag_node = cur; tag_node; tag_node = tag_node->next) {
199                 if (!xmlStrcmp(tag_node->name, (const xmlChar *)TAG_TYPE_PLATFORM_STR))
200                         tag = TAG_TYPE_PLATFORM_STR;
201                 else if (!xmlStrcmp(tag_node->name, (const xmlChar *)TAG_TYPE_CUSTOM_STR))
202                         tag = TAG_TYPE_CUSTOM_STR;
203                 else
204                         continue;
205
206                 cur = tag_node->xmlChildrenNode;
207                 for (cur_node = cur; cur_node ; cur_node = cur_node->next) {
208                         if (cur_node->type != XML_ELEMENT_NODE)
209                                 continue;
210
211                         name = (char *)xmlGetProp(cur_node, (const xmlChar*)"name");
212                         if (!name)
213                                 continue;
214
215                         type = (char *)xmlGetProp(cur_node, (const xmlChar*)"type");
216                         if (!type) {
217                                 xmlFree(name);
218                                 continue;
219                         }
220
221                         value = (char *)xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
222                         if (!value) {
223                                 xmlFree(name);
224                                 xmlFree(type);
225                                 continue;
226                         }
227
228                         if (!strncmp(type, "bool", 4))
229                                 ret = db_set_value_foreach_runtime(db, cur_node, tag, name, type, value);
230                         else
231                                 ret = db_set_value(db, tag, name, type, value, strlen(value));
232
233                         if (ret < 0)
234                                 _E("Failed to set value (%d)", ret);
235
236                         xmlFree(name);
237                         xmlFree(type);
238                         xmlFree(value);
239                 }
240         }
241
242         ret = 0;
243
244 out:
245         if (doc)
246                 xmlFreeDoc(doc);
247         return ret;
248 }
249
250 static struct build_ini_keys {
251         char *info;
252         char *key;
253 } ini_keys[] = {
254         { "version:model",   "http://tizen.org/system/build.model"   },
255         { "version:build",   "http://tizen.org/system/build.string"  },
256         { "version:release", "http://tizen.org/system/build.release" },
257         { "build:type",      "http://tizen.org/system/build.type"    },
258         { "build:date",      "http://tizen.org/system/build.date"    },
259         { "build:time",      "http://tizen.org/system/build.time"    },
260         { "build:variant",   "http://tizen.org/system/build.variant" },
261         { "build:id",        "http://tizen.org/system/build.id"      },
262 };
263
264 static int system_info_get_values_ini(GDBM_FILE *db)
265 {
266         dictionary *ini;
267         int i, ret;
268         char *value;
269
270         if (!db || !*db)
271                 return -EINVAL;
272
273         ini = iniparser_load(INFO_FILE_PATH);
274         if (!ini) {
275                 _E("cannot file open %s file!!!", INFO_FILE_PATH);
276                 return -ENOENT;
277         }
278
279         for (i = 0 ; i < ARRAY_SIZE(ini_keys) ; i++) {
280                 value = iniparser_getstring(ini, ini_keys[i].info, NULL);
281                 if (!value) {
282                         _E("NOT found %s", ini_keys[i].info);
283                         continue;
284                 }
285
286                 ret = db_set_value(db, TAG_TYPE_PLATFORM_STR, ini_keys[i].key, STR_TYPE, value, strlen(value));
287                 if (ret < 0)
288                         _E("Failed to set value (%d)", ret);
289         }
290
291         iniparser_freedict(ini);
292
293         return 0;
294 }
295
296 static int system_info_create_db(void)
297 {
298         int ret;
299         GDBM_FILE db;
300
301         db = gdbm_open(SYSTEM_INFO_DB_PATH, 0, GDBM_WRCREAT, S_IRUSR | S_IRGRP | S_IROTH, NULL);
302         if (!db) {
303                 _E("Failed to open db (%d, %s)", gdbm_errno, gdbm_strerror(gdbm_errno));
304                 return -ENOENT;
305         }
306
307         ret = system_info_get_values_config_xml(&db);
308         if (ret < 0)
309                 _E("Failed to get keys and values from xml(%d)", ret);
310
311         ret = system_info_get_values_ini(&db);
312         if (ret < 0)
313                 _E("Failed to get keys and values from ini(%d)", ret);
314
315         gdbm_close(db);
316
317         return 0;
318 }
319
320 static void show_help(void)
321 {
322         /* TODO : support -l (--lang) option */
323         printf("system_info_init_db [OPTIONS]\n");
324         printf("  -h --help         Show this help\n");
325         printf("  -k --key=KEY      System info key to update\n");
326         printf("  -t --type=TYPE    System info type to update (int/bool/double/string)\n");
327         printf("  -l --lang=LANG    System info specific language target (capi/webapi/csapi)\n");
328         printf("  -g --tag=TAG      System info tag to update (platform/custom)\n");
329         printf("  -v --value=VALUE  System info value to update\n");
330 }
331
332 static int system_info_update_db(int argc, char *argv[])
333 {
334         int ret;
335         GDBM_FILE db;
336         int opt;
337         bool failed = false;
338         char key[KEY_MAX] = {0};
339         char type[KEY_MAX] = {0};
340         char tag[KEY_MAX] = {0};
341         char value[KEY_MAX] = {0};
342         char value_bool[LANG_MAX + 1] = {0};
343         enum language lang = LANG_MAX;
344         int rt;
345
346         struct option long_options[] = {
347                 { "key",   required_argument, 0, 0 },
348                 { "type",  required_argument, 0, 0 },
349                 { "tag",   required_argument, 0, 0 },
350                 { "value", required_argument, 0, 0 },
351                 { "help",  no_argument,       0, 0 },
352                 { 0,       0,                 0, 0 },
353         };
354
355         while (1) {
356                 opt = getopt_long(argc, argv, "k:t:g:v:l:h",
357                                 long_options, NULL);
358                 if (opt < 0)
359                         break;
360                 switch (opt) {
361                 case 'k':
362                         snprintf(key, sizeof(key), "%s", optarg);
363                         break;
364                 case 't':
365                         snprintf(type, sizeof(type), "%s", optarg);
366                         break;
367                 case 'g':
368                         snprintf(tag, sizeof(tag), "%s", optarg);
369                         break;
370                 case 'v':
371                         snprintf(value, sizeof(value), "%s", optarg);
372                         break;
373                 case 'l':
374                         for (rt = 0; rt < LANG_MAX; rt++) {
375                                 if (!runtime[rt].xml_prop)
376                                         break;
377                                 if (!strncmp(optarg, runtime[rt].xml_prop, RT_PREFIX)) {
378                                         lang = runtime[rt].lang;
379                                         break;
380                                 }
381                         }
382                         if (!runtime[rt].xml_prop) {
383                                 printf("Invalid language (%s)\n", optarg);
384                                 return 0;
385                         }
386                         break;
387                 case 'h':
388                 default:
389                         show_help();
390                         return 0;
391                 }
392         }
393
394         failed = false;
395         if (key[0] == '\0') {
396                 printf("Invalid Parameter: no key\n");
397                 failed = true;
398         }
399         if (type[0] == '\0') {
400                 printf("Invalid Parameter: no type\n");
401                 failed = true;
402         }
403         if (tag[0] == '\0') {
404                 printf("Invalid Parameter: no tag\n");
405                 failed = true;
406         }
407         if (value[0] == '\0') {
408                 printf("Invalid Parameter: no value\n");
409                 failed = true;
410         }
411         if ((lang != LANG_MAX) && (strncmp(type, "bool", 4))) {
412                 printf("Invalid Parameter: lang parameter supports for just bool type\n");
413                 failed = true;
414         }
415
416         if (failed)
417                 return -EINVAL;
418
419         if (lang == LANG_MAX)
420                 _I("Request to update: key(%s), type(%s), tag(%s), value(%s)",
421                                 key, type, tag, value);
422         else
423                 _I("Request to update for specific lang(%s): key(%s), type(%s), tag(%s), value(%s)",
424                                 runtime[lang].xml_prop, key, type, tag, value);
425
426         /* http://www.gnu.org.ua/software/gdbm/manual/html_node/Open.html
427          *   If flags is set to ‘GDBM_WRITER’,
428          *   the user wants both read and write access to the database
429          *   and requires exclusive access */
430         db = gdbm_open(SYSTEM_INFO_DB_PATH, 0, GDBM_WRITER, S_IRUSR | S_IRGRP | S_IROTH, NULL);
431         if (!db) {
432                 _E("Failed to open db (%d, %s)", gdbm_errno, gdbm_strerror(gdbm_errno));
433                 return -ENOENT;
434         }
435
436         if (!strncmp(type, "bool", 4)) {
437                 if (lang == LANG_MAX) {
438                         memset(value_bool, value[0] == 't' ? 'T' : 'F', LANG_MAX);
439                         ret = db_set_value(&db, tag, key, type, value_bool, LANG_MAX);
440                 } else
441                         ret = db_set_value_specific_runtime(&db, tag, key, type, value, lang);
442         } else
443                 ret = db_set_value(&db, tag, key, type, value, strlen(value));
444
445         if (ret != 0)
446                 _E("Failed to set value (%d)", ret);
447
448         gdbm_close(db);
449         return ret;
450 }
451
452 int main(int argc, char *argv[])
453 {
454         if (argc == 1)
455                 return system_info_create_db();
456
457         return system_info_update_db(argc, argv);
458 }