3319056b3228404c01fe915097c6ca9e6c4a3002
[platform/core/system/libsystem.git] / src / libsystem / config-parser.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /*
4  * libsystem
5  *
6  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
7  *
8  * Licensed under the Apache License, Version 2.0 (the License);
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <stdbool.h>
26 #include <limits.h>
27
28 #include "libsystem.h"
29 #include "config-parser.h"
30
31 #define MAX_SECTION     64
32
33 static int config_table_lookup(
34                 void *table,
35                 const char *section,
36                 const char *lvalue,
37                 ConfigParserCallback *func,
38                 int *ltype,
39                 void **data) {
40
41         ConfigTableItem *t;
42
43         assert(table);
44         assert(lvalue);
45         assert(func);
46         assert(ltype);
47         assert(data);
48
49         for (t = table; t->lvalue; t++) {
50
51                 if (!streq(lvalue, t->lvalue))
52                         continue;
53
54                 if (!streq_ptr(section, t->section))
55                         continue;
56
57                 *func = t->cb;
58                 *ltype = t->ltype;
59                 *data = t->data;
60                 return 1;
61         }
62
63         return 0;
64 }
65
66 /* Run the user supplied parser for an assignment */
67 static int config_parse_table(
68                 const char *filename,
69                 unsigned line,
70                 void *table,
71                 const char *section,
72                 const char *lvalue,
73                 const char *rvalue) {
74
75         ConfigParserCallback cb = NULL;
76         int ltype = 0;
77         void *data = NULL;
78         int r;
79
80         assert(filename);
81         assert(section);
82         assert(lvalue);
83         assert(rvalue);
84
85         r = config_table_lookup(table,
86                                 section,
87                                 lvalue,
88                                 &cb,
89                                 &ltype,
90                                 &data);
91         if (r <= 0)
92                 return r;
93
94         if (cb)
95                 return cb(filename,
96                           line,
97                           section,
98                           lvalue,
99                           ltype,
100                           rvalue,
101                           data);
102
103         return 0;
104 }
105
106 int config_parse(
107                 const char *filename,
108                 void *table) {
109
110         _cleanup_fclose_ FILE *f = NULL;
111         char *sections[MAX_SECTION] = { 0 };
112         char *section = NULL, *n, *e, l[LINE_MAX];
113         size_t len;
114         int i, r, num_section = 0;
115         bool already;
116         unsigned line = 0;
117
118         assert(filename);
119
120         f = fopen(filename, "r");
121         if (!f)
122                 return -errno;
123
124         while (!feof(f)) {
125                 _cleanup_free_ char *lvalue = NULL, *rvalue = NULL;
126
127                 if (fgets(l, LINE_MAX, f) == NULL) {
128                         if (feof(f))
129                                 break;
130
131                         r = -errno;
132                         goto finish;
133                 }
134
135                 line++;
136                 truncate_nl(l);
137
138                 if (strchr(COMMENTS NEWLINE, *l))
139                         continue;
140
141                 if (*l == '[') {
142                         len = strlen(l);
143                         if (l[len-1] != ']') {
144                                 r = -EBADMSG;
145                                 goto finish;
146                         }
147
148                         n = strndup(l+1, len-2);
149                         if (!n) {
150                                 r = -ENOMEM;
151                                 goto finish;
152                         }
153
154                         already = false;
155                         for (i = 0; i < num_section; i++) {
156                                 if (streq(n, sections[i])) {
157                                         section = sections[i];
158                                         already = true;
159                                         free(n);
160                                         break;
161                                 }
162                         }
163
164                         if (already)
165                                 continue;
166
167                         section = n;
168                         sections[num_section] = n;
169                         num_section++;
170                         if (num_section > MAX_SECTION) {
171                                 r = -EOVERFLOW;
172                                 goto finish;
173                         }
174
175                         continue;
176                 }
177
178                 if (!section)
179                         continue;
180
181                 e = strchr(l, '=');
182                 if (e == NULL)
183                         continue;
184
185                 r = strndup_strip(l, e - l, &lvalue);
186                 if (r < 0)
187                         goto finish;
188
189                 r = strdup_strip(e + 1, &rvalue);
190                 if (r < 0)
191                         goto finish;
192
193                 r = config_parse_table(filename,
194                                        line,
195                                        table,
196                                        section,
197                                        lvalue,
198                                        rvalue);
199                 if (r < 0)
200                         goto finish;
201         }
202
203         r = 0;
204
205 finish:
206         for (i=0; i<num_section; i++)
207                 if (sections[i])
208                         free(sections[i]);
209
210         return r;
211 }
212
213 int config_parse_dir(const char *dir, ConfigParseFunc fp, void *data) {
214         _cleanup_closedir_ DIR *d = NULL;
215         struct dirent *de;
216
217         d = opendir(dir);
218         if (!d)
219                 return errno;
220
221         FOREACH_DIRENT(de, d, return -errno) {
222                 _cleanup_free_ char *path = NULL;
223                 int r;
224
225                 if (de->d_type != DT_REG)
226                         continue;
227
228                 r = asprintf(&path, "%s/%s", dir, de->d_name);
229                 if (r < 0)
230                         return -ENOMEM;
231
232                 /* Do not just break loop until parse all file of
233                  * dir. ignore return */
234                 (void) fp(path, data);
235         }
236
237         return 0;
238 }
239
240 int config_parse_int(
241                 const char *filename,
242                 unsigned line,
243                 const char *section,
244                 const char *lvalue,
245                 int ltype,
246                 const char *rvalue,
247                 void *data) {
248
249         int *i = data;
250
251         assert(filename);
252         assert(lvalue);
253         assert(rvalue);
254         assert(data);
255
256         if (!is_number(rvalue, strlen(rvalue)))
257                 return -EINVAL;
258
259         *i = atoi(rvalue);
260
261         return 0;
262 }
263
264 int config_parse_bool(
265                 const char *filename,
266                 unsigned line,
267                 const char *section,
268                 const char *lvalue,
269                 int ltype,
270                 const char *rvalue,
271                 void *data) {
272
273         int k;
274         bool *b = data;
275
276         assert(filename);
277         assert(lvalue);
278         assert(rvalue);
279         assert(data);
280
281         k = parse_boolean(rvalue);
282         if (k < 0)
283                 return 0;
284
285         *b = !!k;
286         return 0;
287 }
288
289 int config_parse_string(
290                 const char *filename,
291                 unsigned line,
292                 const char *section,
293                 const char *lvalue,
294                 int ltype,
295                 const char *rvalue,
296                 void *data) {
297
298         char **s = data, *n;
299
300         assert(filename);
301         assert(lvalue);
302         assert(rvalue);
303         assert(data);
304
305         if (isempty(rvalue))
306                 n = NULL;
307         else {
308                 n = strdup(rvalue);
309                 if (!n)
310                         return -ENOMEM;
311         }
312
313         free(*s);
314         *s = n;
315
316         return 0;
317 }
318
319 int config_parse_bytes(
320                 const char *filename,
321                 unsigned line,
322                 const char *section,
323                 const char *lvalue,
324                 int ltype,
325                 const char *rvalue,
326                 void *data) {
327
328         size_t *ss = data, s = 0;
329         int r;
330
331         assert(filename);
332         assert(lvalue);
333         assert(rvalue);
334         assert(data);
335
336         if (isempty(rvalue))
337                 s = 0;
338         else {
339                 r = parse_bytes(rvalue, &s);
340                 if (r < 0)
341                         return r;
342         }
343
344         *ss = s;
345
346         return 0;
347 }