Make some macros consistent
[platform/core/api/system-info.git] / src / system_info.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 <gdbm.h>
24 #include <fcntl.h>
25 #include <sys/stat.h>
26 #include <glib.h>
27
28 #include <system_info.h>
29 #include <system_info_private.h>
30 #include <sys/utsname.h>
31
32 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
33 #define KEY_PREFIX "http://"
34
35 #define SYSTEM_INFO_MAX -1
36 #define KEY_MAX 256
37 #define STR_MAX 256
38
39 #define GDBM_CACHE_SIZE 10 /* GDBM default == 100 */
40
41 extern const struct runtime runtime[LANG_MAX];
42
43 GHashTable *hashtable = NULL;
44 static pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER;
45
46 static char *system_info_db_path;
47
48 enum tag_type {
49         TAG_TYPE_PLATFORM,
50         TAG_TYPE_CUSTOM,
51 };
52
53 //LCOV_EXCL_START : not supported feature
54 API int system_info_get_value_int(system_info_key_e key, int *value)
55 {
56         return SYSTEM_INFO_ERROR_NOT_SUPPORTED;
57 }
58
59 API int system_info_get_value_bool(system_info_key_e key, bool *value)
60 {
61         return SYSTEM_INFO_ERROR_NOT_SUPPORTED;
62 }
63
64 API int system_info_get_value_double(system_info_key_e key, double *value)
65 {
66         return SYSTEM_INFO_ERROR_NOT_SUPPORTED;
67 }
68
69 API int system_info_get_value_string(system_info_key_e key, char **value)
70 {
71         return SYSTEM_INFO_ERROR_NOT_SUPPORTED;
72 }
73 //LCOV_EXCL_STOP
74
75 static void destroy_key_value(gpointer data)
76 {
77         free(data);
78 }
79
80 static int db_get_value(enum tag_type tag, const char *key,
81                 const char *type, char *value, size_t len)
82 {
83         char *db_path;
84         char key_internal[KEY_MAX];
85         GDBM_FILE db = NULL;
86         datum d_key;
87         datum d_data;
88         int ret;
89         char *tag_s;
90         int cache_size = GDBM_CACHE_SIZE;
91         char *temp;
92
93         if (!key || !type || !value)
94                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
95
96         switch (tag) {
97         case TAG_TYPE_PLATFORM:
98                 tag_s = TAG_TYPE_PLATFORM_STR;
99                 break;
100         case TAG_TYPE_CUSTOM:
101                 tag_s = TAG_TYPE_CUSTOM_STR;
102                 break;
103         default:
104                 return -EINVAL;
105         }
106
107         if (strstr(key, KEY_PREFIX) == key)
108                 snprintf(key_internal, sizeof(key_internal), "%s:%s:%s", key, type, tag_s);
109         else
110                 snprintf(key_internal, sizeof(key_internal), "%s%s:%s:%s", KEY_PREFIX, key, type, tag_s);
111
112         pthread_mutex_lock(&fmutex);
113         if (!hashtable) {
114                 hashtable = g_hash_table_new_full(g_str_hash, g_str_equal, destroy_key_value, destroy_key_value);
115         } else {
116                 temp = (char *)g_hash_table_lookup(hashtable, key_internal);
117                 if (temp) {
118                         snprintf(value, len, "%s", temp);
119                         pthread_mutex_unlock(&fmutex);
120                         return SYSTEM_INFO_ERROR_NONE;
121                 }
122         }
123
124         if (access(SYSTEM_INFO_DB_RW_PATH, R_OK) == 0)
125                 db_path = SYSTEM_INFO_DB_RW_PATH;
126         else
127                 db_path = SYSTEM_INFO_DB_RO_PATH;
128
129         db = gdbm_open(db_path, 0, GDBM_READER, S_IRUSR | S_IRGRP | S_IROTH, NULL);
130         if (!db) {
131                 _E("Failed to open db (%d, %s)", gdbm_errno, gdbm_strerror(gdbm_errno)); //LCOV_EXCL_LINE
132                 pthread_mutex_unlock(&fmutex);
133                 return SYSTEM_INFO_ERROR_IO_ERROR; //LCOV_EXCL_LINE
134         }
135
136         ret = gdbm_setopt(db, GDBM_CACHESIZE, &cache_size, sizeof(cache_size));
137         if (ret < 0)
138                 _E("Failed to set cache size to (%d) (ret:%d)", cache_size, gdbm_errno); //LCOV_EXCL_LINE
139
140         d_key.dptr = key_internal;
141         d_key.dsize = strlen(key_internal) + 1;
142
143         d_data = gdbm_fetch(db, d_key);
144         if (!d_data.dptr) {
145                 _E("Failed to find key (%s, %s)", key, type);
146                 ret = SYSTEM_INFO_ERROR_INVALID_PARAMETER;
147                 goto out;
148         }
149
150         if (len <= d_data.dsize) {
151                 _E("Buffer size is smaller than DB value size. It can be cut");
152                 d_data.dsize = len - 1;
153         }
154
155         memcpy(value, d_data.dptr, d_data.dsize);
156         value[d_data.dsize] = '\0';
157         free(d_data.dptr);
158         ret = SYSTEM_INFO_ERROR_NONE;
159
160         g_hash_table_insert(hashtable, strdup(key_internal), strdup(value));
161 out:
162         if (db)
163                 gdbm_close(db);
164         pthread_mutex_unlock(&fmutex);
165         return ret;
166 }
167
168 struct sysinfo_type {
169         system_info_type_e type_e;
170         const char *type_str;
171 } info_type[] = {
172         { SYSTEM_INFO_BOOL,   BOOL_TYPE },
173         { SYSTEM_INFO_INT,    INT_TYPE  },
174         { SYSTEM_INFO_DOUBLE, DBL_TYPE  },
175         { SYSTEM_INFO_STRING, STR_TYPE  },
176 };
177
178 static int system_info_get_type(enum tag_type tag, const char *key,
179                 system_info_type_e *type)
180 {
181         char key_internal[KEY_MAX];
182         GDBM_FILE db = NULL;
183         datum d_key;
184         datum d_data;
185         int ret, i;
186         char *tag_s;
187         int cache_size = GDBM_CACHE_SIZE;
188         char *temp;
189
190         if (!key || !type)
191                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
192
193         switch (tag) {
194         case TAG_TYPE_PLATFORM:
195                 tag_s = TAG_TYPE_PLATFORM_STR;
196                 break;
197         case TAG_TYPE_CUSTOM:
198                 tag_s = TAG_TYPE_CUSTOM_STR;
199                 break;
200         default:
201                 return -EINVAL;
202         }
203
204         pthread_mutex_lock(&fmutex);
205         if (!hashtable) {
206                 hashtable = g_hash_table_new_full(g_str_hash, g_str_equal, destroy_key_value, destroy_key_value);
207         } else {
208                 for (i = 0 ; i < ARRAY_SIZE(info_type); i++) {
209                         if (strstr(key, KEY_PREFIX) == key)
210                                 snprintf(key_internal, sizeof(key_internal),
211                                                 "%s:%s:%s", key, info_type[i].type_str, tag_s);
212                         else
213                                 snprintf(key_internal, sizeof(key_internal),
214                                                 "%s%s:%s:%s", KEY_PREFIX, key, info_type[i].type_str, tag_s);
215                         temp = g_hash_table_lookup(hashtable, key_internal);
216                         if (!temp)
217                                 continue;
218
219                         *type = info_type[i].type_e;
220                         pthread_mutex_unlock(&fmutex);
221                         return SYSTEM_INFO_ERROR_NONE;
222                 }
223         }
224
225         if (!system_info_db_path) {
226                 if (access(SYSTEM_INFO_DB_RW_PATH, R_OK) == 0)
227                         system_info_db_path = SYSTEM_INFO_DB_RW_PATH;
228                 else
229                         system_info_db_path = SYSTEM_INFO_DB_RO_PATH;
230         }
231
232         db = gdbm_open(system_info_db_path, 0, GDBM_READER, S_IRUSR | S_IRGRP | S_IROTH, NULL);
233         if (!db) {
234                 _E("Failed to open db (%d, %s)", gdbm_errno, gdbm_strerror(gdbm_errno)); //LCOV_EXCL_LINE
235                 pthread_mutex_unlock(&fmutex);
236                 return SYSTEM_INFO_ERROR_IO_ERROR; //LCOV_EXCL_LINE
237         }
238
239         ret = gdbm_setopt(db, GDBM_CACHESIZE, &cache_size, sizeof(cache_size));
240         if (ret < 0)
241                 _E("Failed to set cache size to (%d) (ret:%d)", cache_size, gdbm_errno); //LCOV_EXCL_LINE
242
243         for (i = 0 ; i < ARRAY_SIZE(info_type); i++) {
244                 if (strstr(key, KEY_PREFIX) == key)
245                         snprintf(key_internal, sizeof(key_internal),
246                                         "%s:%s:%s", key, info_type[i].type_str, tag_s);
247                 else
248                         snprintf(key_internal, sizeof(key_internal),
249                                         "%s%s:%s:%s", KEY_PREFIX, key, info_type[i].type_str, tag_s);
250
251                 d_key.dptr = key_internal;
252                 d_key.dsize = strlen(key_internal) + 1;
253
254                 d_data = gdbm_fetch(db, d_key);
255                 if (d_data.dptr) {
256                         *type = info_type[i].type_e;
257                         ret = SYSTEM_INFO_ERROR_NONE;
258
259                         g_hash_table_insert(hashtable, strndup(key_internal, d_key.dsize),
260                                         strndup(d_data.dptr, d_data.dsize));
261                         free(d_data.dptr);
262                         goto out;
263                 }
264         }
265
266         if (tag == TAG_TYPE_PLATFORM)
267                 ret = system_info_get_type_file(key, type);
268         else
269                 ret = SYSTEM_INFO_ERROR_INVALID_PARAMETER;
270
271 out:
272         if (db)
273                 gdbm_close(db);
274         pthread_mutex_unlock(&fmutex);
275         return ret;
276 }
277
278 static int system_info_get_bool(enum tag_type tag, const char *key, bool *value)
279 {
280         int ret;
281         char val[16];
282         char *valp;
283         size_t len;
284         const char *runtime_type;
285         int rt;
286
287         if (!key || !value)
288                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
289
290         ret = db_get_value(tag, key, BOOL_TYPE, val, sizeof(val));
291         if (ret == SYSTEM_INFO_ERROR_NONE) {
292                 runtime_type = getenv("RUNTIME_TYPE");
293                 if (runtime_type) {
294                         for (rt = 0; rt < LANG_MAX; rt++) {
295                                 if (!runtime[rt].runtime_type)
296                                         break;
297                                 if (!strncmp(runtime_type, runtime[rt].runtime_type, RT_PREFIX)) {
298                                         *value = val[runtime[rt].lang] == 'T' ? true : false;
299                                         return SYSTEM_INFO_ERROR_NONE;
300                                 }
301                         }
302                         _D("Unknown RUNTIME_TYPE, return default value");
303                 }
304
305                 *value = val[runtime[DEFAULT].lang] == 'T' ? true : false;
306                 return SYSTEM_INFO_ERROR_NONE;
307         }
308
309         if (tag == TAG_TYPE_CUSTOM) {
310                 ret = external_get_value(TAG_TYPE_CUSTOM_STR, key, BOOL_TYPE, &valp);
311                 if (ret == SYSTEM_INFO_ERROR_NONE) {
312                         snprintf(val, sizeof(val), "%s", valp); //LCOV_EXCL_LINE
313                         free(valp); //LCOV_EXCL_LINE
314
315                         len = strlen(val) + 0;
316                         if (!strncmp(val, "true", len) || !strncmp(val, "TRUE", len))
317                                 *value = true;
318                         else
319                                 *value = false;
320
321                         return SYSTEM_INFO_ERROR_NONE;
322                 }
323         }
324
325         _E("Invalid key (%s), type:bool", key);
326
327         return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
328 }
329
330 static int system_info_get_int(enum tag_type tag, const char *key, int *value)
331 {
332         int ret;
333         char val[128];
334         char *valp;
335
336         if (!key || !value)
337                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
338
339         ret = db_get_value(tag, key, INT_TYPE, val, sizeof(val));
340         if (ret == SYSTEM_INFO_ERROR_NONE)
341                 goto out;
342
343         if (tag == TAG_TYPE_CUSTOM) {
344                 ret = external_get_value(TAG_TYPE_CUSTOM_STR, key, INT_TYPE, &valp);
345                 if (ret == SYSTEM_INFO_ERROR_NONE) {
346                         snprintf(val, sizeof(val), "%s", valp); //LCOV_EXCL_LINE
347                         free(valp); //LCOV_EXCL_LINE
348                         goto out; //LCOV_EXCL_LINE
349                 }
350         }
351
352         _E("Invalid key (%s), type:integer", key);
353
354         return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
355
356 out:
357         *value = atoi(val);
358
359         return SYSTEM_INFO_ERROR_NONE;
360 }
361
362 static int system_info_get_double(enum tag_type tag, const char *key, double *value)
363 {
364         int ret;
365         char val[128];
366         char *valp;
367
368         if (!key || !value)
369                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
370
371         ret = db_get_value(tag, key, DBL_TYPE, val, sizeof(val));
372         if (ret == SYSTEM_INFO_ERROR_NONE)
373                 goto out;
374
375         if (tag == TAG_TYPE_CUSTOM) {
376                 ret = external_get_value(TAG_TYPE_CUSTOM_STR, key, DBL_TYPE, &valp);
377                 if (ret == SYSTEM_INFO_ERROR_NONE) {
378                         snprintf(val, sizeof(val), "%s", valp); //LCOV_EXCL_LINE
379                         free(valp); //LCOV_EXCL_LINE
380                         goto out; //LCOV_EXCL_LINE
381                 }
382         }
383
384         _E("Invalid key (%s), type:double", key);
385
386         return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
387
388 out:
389         *value = atof(val);
390
391         return SYSTEM_INFO_ERROR_NONE;
392 }
393
394 static int system_info_get_string(enum tag_type tag, const char *key, char **value)
395 {
396         int ret;
397         char val[STR_MAX];
398         char *string;
399         char *valp;
400
401         if (!key || !value)
402                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
403
404         ret = db_get_value(tag, key, STR_TYPE, val, sizeof(val));
405         if (ret == SYSTEM_INFO_ERROR_NONE)
406                 goto out;
407
408         if (tag == TAG_TYPE_PLATFORM) {
409                 ret = system_info_get_file(key, val, sizeof(val));
410                 if (ret == SYSTEM_INFO_ERROR_NONE)
411                         goto out;
412         }
413
414         if (tag == TAG_TYPE_CUSTOM) {
415                 ret = external_get_value(TAG_TYPE_CUSTOM_STR, key, DBL_TYPE, &valp);
416                 if (ret == SYSTEM_INFO_ERROR_NONE) {
417                         snprintf(val, sizeof(val), "%s", valp); //LCOV_EXCL_LINE
418                         free(valp); //LCOV_EXCL_LINE
419                         goto out; //LCOV_EXCL_LINE
420                 }
421         }
422
423         _E("Invalid key (%s) type:string", key);
424
425         return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
426
427 out:
428         string = strdup(val);
429         if (!string) {
430                 _E("malloc failed"); //LCOV_EXCL_LINE
431                 return SYSTEM_INFO_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
432         }
433
434         *value = string;
435
436         return SYSTEM_INFO_ERROR_NONE;
437 }
438
439 API int system_info_get_platform_bool(const char *key, bool *value)
440 {
441         return system_info_get_bool(TAG_TYPE_PLATFORM, key, value);
442 }
443
444 API int system_info_get_platform_int(const char *key, int *value)
445 {
446         return system_info_get_int(TAG_TYPE_PLATFORM, key, value);
447 }
448
449 API int system_info_get_platform_double(const char *key, double *value)
450 {
451         return system_info_get_double(TAG_TYPE_PLATFORM, key, value);
452 }
453
454 API int system_info_get_platform_string(const char *key, char **value)
455 {
456         return system_info_get_string(TAG_TYPE_PLATFORM, key, value);
457 }
458
459 API int system_info_get_custom_bool(const char *key, bool *value)
460 {
461         return system_info_get_bool(TAG_TYPE_CUSTOM, key, value);
462 }
463
464 API int system_info_get_custom_int(const char *key, int *value)
465 {
466         return system_info_get_int(TAG_TYPE_CUSTOM, key, value);
467 }
468
469 API int system_info_get_custom_double(const char *key, double *value)
470 {
471         return system_info_get_double(TAG_TYPE_CUSTOM, key, value);
472 }
473
474 API int system_info_get_custom_string(const char *key, char **value)
475 {
476         return system_info_get_string(TAG_TYPE_CUSTOM, key, value);
477 }
478
479 API int system_info_get_platform_type(const char *key, system_info_type_e *type)
480 {
481         return system_info_get_type(TAG_TYPE_PLATFORM, key, type);
482 }
483
484 API int system_info_get_custom_type(const char *key, system_info_type_e *type)
485 {
486         int ret;
487         char *val = NULL;
488         size_t len;
489
490         ret = system_info_get_type(TAG_TYPE_CUSTOM, key, type);
491         if (ret == SYSTEM_INFO_ERROR_NONE)
492                 return SYSTEM_INFO_ERROR_NONE;
493
494         ret = external_get_type(TAG_TYPE_CUSTOM_STR, key, &val);
495         if (ret != SYSTEM_INFO_ERROR_NONE) {
496                 _E("Failed to get type of key (%s)", key);
497                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
498         }
499
500         //LCOV_EXCL_START
501         len = strlen(val) + 1;
502         if (!strncmp(BOOL_TYPE, val, len))
503                 *type = SYSTEM_INFO_BOOL;
504         else if (!strncmp(INT_TYPE, val, len))
505                 *type = SYSTEM_INFO_INT;
506         else if (!strncmp(DBL_TYPE, val, len))
507                 *type = SYSTEM_INFO_DOUBLE;
508         else if (!strncmp(STR_TYPE, val, len))
509                 *type = SYSTEM_INFO_STRING;
510         else {
511                 _E("Invalid type (%s)", val);
512                 free(val);
513                 return SYSTEM_INFO_ERROR_INVALID_PARAMETER;
514         }
515
516         free(val);
517         return SYSTEM_INFO_ERROR_NONE;
518         //LCOV_EXCL_STOP
519 }