Explict type cast according to iniparser 4.1 API change
[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, const char *path)
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(path);
175         if (!doc) {
176                 _E("cannot file open %s file!!!", path);
177                 return SYSTEM_INFO_ERROR_IO_ERROR;
178         }
179
180         cur = xmlDocGetRootElement(doc);
181         if (!cur) {
182                 _E("empty document %s 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 = (char*)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(const char *conf_path, char *db_path)
297 {
298         int ret;
299         GDBM_FILE db;
300
301         if (conf_path == NULL)
302                 conf_path = MODEL_CONFIG_RO_PATH;
303
304         if (db_path == NULL)
305                 db_path = SYSTEM_INFO_DB_RO_PATH;
306
307         db = gdbm_open(db_path, 0, GDBM_WRCREAT, S_IRUSR | S_IRGRP | S_IROTH, NULL);
308         if (!db) {
309                 _E("Failed to open db (%d, %s)", gdbm_errno, gdbm_strerror(gdbm_errno));
310                 return -ENOENT;
311         }
312
313         ret = system_info_get_values_config_xml(&db, conf_path);
314         if (ret < 0)
315                 _E("Failed to get keys and values from xml(%d)", ret);
316
317         ret = system_info_get_values_ini(&db);
318         if (ret < 0)
319                 _E("Failed to get keys and values from ini(%d)", ret);
320
321         gdbm_close(db);
322
323         return 0;
324 }
325
326 static void show_help(void)
327 {
328         /* TODO : support -l (--lang) option */
329         printf("system_info_init_db [OPTIONS]\n");
330         printf("  -h --help         Show this help\n");
331         printf("  -k --key=KEY      System info key to update\n");
332         printf("  -t --type=TYPE    System info type to update (int/bool/double/string)\n");
333         printf("  -l --lang=LANG    System info specific language target (capi/webapi/csapi)\n");
334         printf("  -g --tag=TAG      System info tag to update (platform/custom)\n");
335         printf("  -v --value=VALUE  System info value to update\n");
336         printf("  -i --input=PATH   System info get input argument from several source\n");
337         printf("  -o --output=PATH  System info get output argument from several source\n");
338 }
339
340 static int system_info_update_db(int argc, char *argv[])
341 {
342         int ret;
343         GDBM_FILE db;
344         int opt;
345         bool failed = false;
346         char key[KEY_MAX] = {0};
347         char type[KEY_MAX] = {0};
348         char tag[KEY_MAX] = {0};
349         char value[KEY_MAX] = {0};
350         char value_bool[LANG_MAX + 1] = {0};
351         char conf_path[KEY_MAX] = {0};
352         char db_path[KEY_MAX] = {0};
353         enum language lang = LANG_MAX;
354         int rt;
355
356         struct option long_options[] = {
357                 { "key",   required_argument, 0, 0 },
358                 { "type",  required_argument, 0, 0 },
359                 { "tag",   required_argument, 0, 0 },
360                 { "value", required_argument, 0, 0 },
361                 { "input", required_argument, 0, 0 },
362                 { "output", required_argument, 0, 0 },
363                 { "help",  no_argument,       0, 0 },
364                 { 0,       0,                 0, 0 },
365         };
366
367         while (1) {
368                 opt = getopt_long(argc, argv, "k:t:g:v:l:i:o:h",
369                                 long_options, NULL);
370                 if (opt < 0)
371                         break;
372                 switch (opt) {
373                 case 'k':
374                         snprintf(key, sizeof(key), "%s", optarg);
375                         break;
376                 case 't':
377                         snprintf(type, sizeof(type), "%s", optarg);
378                         break;
379                 case 'g':
380                         snprintf(tag, sizeof(tag), "%s", optarg);
381                         break;
382                 case 'v':
383                         snprintf(value, sizeof(value), "%s", optarg);
384                         break;
385                 case 'i':
386                         snprintf(conf_path, sizeof(conf_path), "%s", optarg);
387                         break;
388                 case 'o':
389                         snprintf(db_path, sizeof(db_path), "%s", optarg);
390                         break;
391                 case 'l':
392                         for (rt = 0; rt < LANG_MAX; rt++) {
393                                 if (!runtime[rt].xml_prop)
394                                         break;
395                                 if (!strncmp(optarg, runtime[rt].xml_prop, RT_PREFIX)) {
396                                         lang = runtime[rt].lang;
397                                         break;
398                                 }
399                         }
400                         if (rt == LANG_MAX || !runtime[rt].xml_prop) {
401                                 printf("Invalid language (%s)\n", optarg);
402                                 return 0;
403                         }
404                         break;
405                 case 'h':
406                 default:
407                         show_help();
408                         return 0;
409                 }
410         }
411
412         if (conf_path[0] != '\0' && db_path[0] != '\0') {
413                 printf("Make system info db(%s) by %s\n", db_path, conf_path);
414                 return system_info_create_db(conf_path, db_path);
415         }
416
417         failed = false;
418         if (key[0] == '\0') {
419                 printf("Invalid Parameter: no key\n");
420                 failed = true;
421         }
422         if (type[0] == '\0') {
423                 printf("Invalid Parameter: no type\n");
424                 failed = true;
425         }
426         if (tag[0] == '\0') {
427                 printf("Invalid Parameter: no tag\n");
428                 failed = true;
429         }
430         if (value[0] == '\0') {
431                 printf("Invalid Parameter: no value\n");
432                 failed = true;
433         }
434         if ((lang != LANG_MAX) && (strncmp(type, "bool", 4))) {
435                 printf("Invalid Parameter: lang parameter supports for just bool type\n");
436                 failed = true;
437         }
438
439         if (failed)
440                 return -EINVAL;
441
442         if (lang == LANG_MAX)
443                 _I("Request to update: key(%s), type(%s), tag(%s), value(%s)",
444                                 key, type, tag, value);
445         else
446                 _I("Request to update for specific lang(%s): key(%s), type(%s), tag(%s), value(%s)",
447                                 runtime[lang].xml_prop, key, type, tag, value);
448
449         /* http://www.gnu.org.ua/software/gdbm/manual/html_node/Open.html
450          *   If flags is set to ‘GDBM_WRITER’,
451          *   the user wants both read and write access to the database
452          *   and requires exclusive access */
453         db = gdbm_open(SYSTEM_INFO_DB_RO_PATH, 0, GDBM_WRITER, S_IRUSR | S_IRGRP | S_IROTH, NULL);
454         if (!db) {
455                 _E("Failed to open db (%d, %s)", gdbm_errno, gdbm_strerror(gdbm_errno));
456                 return -ENOENT;
457         }
458
459         if (!strncmp(type, "bool", 4)) {
460                 if (lang == LANG_MAX) {
461                         memset(value_bool, value[0] == 't' ? 'T' : 'F', LANG_MAX);
462                         ret = db_set_value(&db, tag, key, type, value_bool, LANG_MAX);
463                 } else
464                         ret = db_set_value_specific_runtime(&db, tag, key, type, value, lang);
465         } else
466                 ret = db_set_value(&db, tag, key, type, value, strlen(value));
467
468         if (ret != 0)
469                 _E("Failed to set value (%d)", ret);
470
471         gdbm_close(db);
472         return ret;
473 }
474
475 int main(int argc, char *argv[])
476 {
477         if (argc == 1)
478                 return system_info_create_db(NULL, NULL);
479
480         return system_info_update_db(argc, argv);
481 }