init_db: exclude hal-release information from database
[platform/core/api/system-info.git] / tool / system-info-tool-set.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <getopt.h>
6 #include <errno.h>
7 #include <sys/file.h>
8
9 #include "system-info-tool.h"
10 #include "system-info-tool-get.h"
11 #include "system-info-tool-set.h"
12
13 void system_info_tool_set_help(void)
14 {
15         printf("  -s|--set KEY TYPE VALUE        Add or update user-defined KEY\n");
16         printf("                                 Available TYPE: bool, int, double, string\n");
17         printf("                                 ex) system-info-tool -s tizen.org/feature/display bool true\n");
18         printf("                                     system-info-tool -s tizen.org/system/manufacturer string Tizen\n");
19         printf("  -c|--clear KEY                 Clear user-defined KEY. This cannot clear read-only system key\n");
20         printf("  -C|--clear-all                 Clear all user-defined keys\n");
21 }
22
23 static int convert_raw_value(const char *rawtype, const char *rawvalue, struct value *out)
24 {
25         system_info_type_e type = string_to_type(rawtype);
26
27         if (type == SYSTEM_INFO_TYPE_MAX) {
28                 printf("Invalid type \"%s\"\n", rawtype);
29                 return -EINVAL;
30         }
31
32         out->type = type;
33
34         if (type == SYSTEM_INFO_BOOL) {
35                 int tmpbool;
36                 if (sscanf(rawvalue, "%d", &tmpbool) == 1) {
37                         out->b = tmpbool;
38                         return 0;
39                 } else if (strncasecmp(rawvalue, "true", sizeof("true")) == 0) {
40                         out->b = true;
41                         return 0;
42                 } else if (strncasecmp(rawvalue, "false", sizeof("false")) == 0) {
43                         out->b = false;
44                         return 0;
45                 }
46                 printf("Invalid bool value \"%s\"\n", rawvalue);
47         } else if (type == SYSTEM_INFO_INT) {
48                 if (sscanf(rawvalue, "%d", &out->i) == 1)
49                         return 0;
50                 printf("Invalid int value \"%s\"\n", rawvalue);
51         } else if (type == SYSTEM_INFO_DOUBLE) {
52                 if (sscanf(rawvalue, "%lf", &out->d) == 1)
53                         return 0;
54                 printf("Invalid double value \"%s\"\n", rawvalue);
55         } else if (type == SYSTEM_INFO_STRING) {
56                 out->s = strndup(rawvalue, BUFFER_MAX);
57                 return 0;
58         }
59
60         return -EINVAL;
61 }
62
63 static int try_flock(FILE *fp, bool blocking)
64 {
65         int fd = -1;
66         int retval;
67         int flags = LOCK_EX;
68
69         if (!fp)
70                 return -EBADF;
71
72         fd = fileno(fp);
73         if (fd < 0)
74                 return -errno;
75
76         if (blocking == false)
77                 flags |= LOCK_NB;
78
79         retval = flock(fd, flags);
80         if (retval != 0) {
81                 if (errno == EWOULDBLOCK)
82                         printf("User-defined database is now being accessed by someone. Try again\n");
83                 else
84                         printf("Failed to acquire exclusive flock, %m\n");
85                 return -errno;
86         }
87
88         return 0;
89 }
90
91 static int add_new_entry(const char *key, struct value value)
92 {
93         char dbpath[BUFFER_MAX];
94         char internal_key[BUFFER_MAX] = {0, };
95         char internal_value[BUFFER_MAX] = {0, };
96         int retval;
97         __auto_fclose__ FILE *fp = NULL;
98
99         if (!key)
100                 return -EINVAL;
101
102         /* make internal_key */
103         snprintf(internal_key, sizeof(internal_key), "platform:%s:%s", key, type_to_string(value.type));
104
105         /* make internal_value */
106         if (value.type == SYSTEM_INFO_BOOL) {
107                 if (value.b == true)
108                         snprintf(internal_value, sizeof(internal_value), "TTTTTTTT");
109                 else
110                         snprintf(internal_value, sizeof(internal_value), "FFFFFFFF");
111         } else if (value.type == SYSTEM_INFO_INT) {
112                 snprintf(internal_value, sizeof(internal_value), "%d", value.i);
113         } else if (value.type == SYSTEM_INFO_DOUBLE) {
114                 snprintf(internal_value, sizeof(internal_value), "%lf", value.d);
115         } else if (value.type == SYSTEM_INFO_STRING) {
116                 snprintf(internal_value, sizeof(internal_value), "%s", value.s);
117         } else {
118                 return -EINVAL;
119         }
120
121         snprintf(dbpath, sizeof(dbpath), "%s/%lu", SYSTEM_INFO_DB_RW_PATH, simple_hash(internal_key));
122         fp = fopen(dbpath, "a");
123         if (!fp)
124                 return -errno;
125
126         retval = try_flock(fp, false);
127         if (retval < 0)
128                 return retval;
129
130         retval = fprintf(fp, "%s %s\n", internal_key, internal_value);
131         if (retval < 0)
132                 return -EIO;
133
134         return 0;
135 }
136
137 static int remove_entry(const char *key, system_info_type_e type)
138 {
139         char dbpath[BUFFER_MAX];
140         char backup[BUFFER_MAX];
141         char internal_key[BUFFER_MAX];
142         char line[BUFFER_MAX * 8];
143         char readkey[BUFFER_MAX];
144         char readtype[BUFFER_MAX];
145         __auto_fclose__ FILE *fp1 = NULL;
146         __auto_fclose__ FILE *fp2 = NULL;
147         int retval;
148
149         if (!key)
150                 return -EINVAL;
151
152         if (type < SYSTEM_INFO_TYPE_MIN || type >= SYSTEM_INFO_TYPE_MAX)
153                 return -EINVAL;
154
155         /* make internal_key */
156         snprintf(internal_key, sizeof(internal_key), "platform:%s:%s", key, type_to_string(type));
157
158         snprintf(dbpath, sizeof(dbpath), "%s/%lu", SYSTEM_INFO_DB_RW_PATH, simple_hash(internal_key));
159         fp1 = fopen(dbpath, "r+");
160         if (!fp1)
161                 return -errno;
162
163         retval = try_flock(fp1, false);
164         if (retval < 0)
165                 return retval;
166
167         snprintf(backup, sizeof(backup), "%s/.backup.%lu", SYSTEM_INFO_DB_RW_PATH, simple_hash(internal_key));
168         fp2 = fopen(backup, "w+");
169         if (!fp2)
170                 return -errno;
171
172         while ((fgets(line, sizeof(line), fp1))) {
173                 retval = sscanf(line, "platform:%127s:%127s", readkey, readtype);
174                 if (retval != 2)
175                         continue;
176
177                 if (strncmp(readkey, key, sizeof(readkey)) == 0
178                         && string_to_type(readtype) == type)
179                         continue;
180
181                 fprintf(fp2, "%s", line);
182         }
183
184         if (truncate(dbpath, 0) < 0)
185                 printf("Failed to reset database, %m\n");
186
187         rewind(fp1);
188         rewind(fp2);
189
190         while ((fgets(line, sizeof(line), fp2)))
191                 fprintf(fp1, "%s", line);
192
193         unlink(backup);
194
195         return 0;
196 }
197
198 static int modify_entry(const char *key, struct value value)
199 {
200         int ret;
201
202         ret = remove_entry(key, value.type);
203         if (ret < 0)
204                 return ret;
205
206         return add_new_entry(key, value);
207 }
208
209 static int system_info_tool_set_entry(const char *key, struct value value)
210 {
211         __auto_free_dbentry__ struct dbentry dbentry = {0, };
212         int retval;
213
214         if (!key)
215                 return -EINVAL;
216
217         retval = system_info_tool_get_raw(key, value.type, DB_DEFAULT_RW, &dbentry);
218         if (retval == 0)
219                 return modify_entry(key, value);
220         else
221                 return add_new_entry(key, value);
222 }
223
224 static int system_info_tool_init_rw_database(void)
225 {
226         return system("/usr/bin/mkdir -p "SYSTEM_INFO_DB_RW_PATH);
227 }
228
229 int system_info_tool_set(int argc, char *argv[])
230 {
231         int ret;
232         char key[BUFFER_MAX];
233         struct value value;
234
235         /* argv[optind]    : key
236          * argv[optind + 1]: type
237          * argv[optind + 2]: value
238          * check if there is at least 3 arguments */
239         if (argc - optind < 3) {
240                 printf("Need key, type, value\n");
241                 return -EINVAL;
242         }
243
244         if (access(SYSTEM_INFO_DB_RW_PATH, F_OK) != 0) {
245                 ret = system_info_tool_init_rw_database();
246                 if (ret != 0)
247                         return -ENOTSUP;
248         }
249
250         ret = convert_raw_key(argv[optind], key, sizeof(key));
251         if (ret < 0)
252                 return ret;
253
254         ret = convert_raw_value(argv[optind + 1], argv[optind + 2], &value);
255         if (ret < 0)
256                 return ret;
257
258         return system_info_tool_set_entry(key, value);
259 }
260
261 int system_info_tool_clear_key(const char *rawkey)
262 {
263         int retval;
264         int ret;
265         int match = 0;
266         int i;
267         int select;
268         char key[BUFFER_MAX];
269
270         struct cache {
271                 int match;
272                 struct dbentry dbentry;
273         } cache[SYSTEM_INFO_TYPE_MAX] = {
274                 { -1, },
275                 { -1, },
276                 { -1, },
277                 { -1, },
278         };
279
280         ret = convert_raw_key(rawkey, key, sizeof(key));
281         if (ret < 0)
282                 return ret;
283
284         for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) {
285                 retval = system_info_tool_get_raw(key, i, DB_DEFAULT_RW, &cache[i].dbentry);
286                 if (retval == 0)
287                         cache[i].match = ++match;
288         }
289
290         if (match == 1) {
291                 for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) {
292                         if (cache[i].match == match) {
293                                 ret = remove_entry(cache[i].dbentry.key, cache[i].dbentry.value.type);
294                                 goto out;
295                         }
296                 }
297         } else if (match > 1) {
298                 printf("There is multiple same keys with different type. Which type to clear?\n");
299                 for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i)
300                         if (cache[i].match > 0) {
301                                 printf(" [%d] ", cache[i].match);
302                                 print_value(cache[i].dbentry.value);
303                         }
304
305                 printf("Select: ");
306                 retval = scanf("%d", &select);
307                 if (retval != 1) {
308                         printf("Invalid selection\n");
309                         ret = -EINVAL;
310                         goto out;
311                 }
312
313                 for (i = 0; i < SYSTEM_INFO_TYPE_MAX; ++i) {
314                         if (cache[i].match == select) {
315                                 ret = remove_entry(cache[i].dbentry.key, cache[i].dbentry.value.type);
316                                 goto out;
317                         }
318                 }
319         }
320
321         printf("user-defined key=%s is not found\n", key);
322         ret = -ENOENT;
323
324 out:
325         if (cache[SYSTEM_INFO_STRING].match > 0)
326                 free(cache[SYSTEM_INFO_STRING].dbentry.value.s);
327
328         return ret;
329 }
330
331 void system_info_tool_clear_all(void)
332 {
333         char dbpath[BUFFER_MAX];
334         int retval;
335
336         for (int i = 0; i < NUM_HASH_FILE; ++i) {
337                 __auto_fclose__ FILE *fp = NULL;
338                 snprintf(dbpath, sizeof(dbpath), "%s/%d", SYSTEM_INFO_DB_RW_PATH, i);
339                 fp = fopen(dbpath, "r");
340                 if (!fp)
341                         continue;
342
343                 retval = try_flock(fp, true);
344                 if (retval < 0)
345                         continue;
346
347                 if (truncate(dbpath, 0) < 0)
348                         printf("Failed to reset database, %m\n");
349                 unlink(dbpath);
350         }
351 }