Modify comments & remove useless things
[platform/core/system/resourced.git] / src / common / config-parser.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include <limits.h>
24
25 #include "util.h"
26 #include "trace.h"
27 #include "config-parser.h"
28
29 #define MAX_SECTION     64
30
31 int config_parse(const char *file_name, int cb(struct parse_result *result,
32                         void *user_data), void *user_data)
33 {
34         FILE *f = NULL;
35         struct parse_result result;
36         /* use stack for parsing */
37         char line[LINE_MAX];
38         char section[MAX_SECTION];
39         char *start, *end, *name, *value;
40         int lineno = 0, ret = 0;
41
42         if (!file_name || !cb) {
43                 ret = -EINVAL;
44                 goto error;
45         }
46
47         /* open conf file */
48         f = fopen(file_name, "r");
49         if (!f) {
50                 _E("Failed to open file %s", file_name);
51                 ret = -EIO;
52                 goto error;
53         }
54
55         /* parsing line by line */
56         while (fgets(line, LINE_MAX, f) != NULL) {
57                 lineno++;
58
59                 start = line;
60                 truncate_nl(start);
61                 start = strstrip(start);
62
63                 if (*start == COMMENT) {
64                         continue;
65                 } else if (*start == '[') {
66                         /* parse section */
67                         end = strchr(start, ']');
68                         if (!end || *end != ']') {
69                                 ret = -EBADMSG;
70                                 goto error;
71                         }
72
73                         *end = '\0';
74                         strncpy(section, start + 1, sizeof(section)-1);
75                         section[MAX_SECTION-1] = '\0';
76                 } else if (*start) {
77                         /* parse name & value */
78                         end = strchr(start, '=');
79                         if (!end || *end != '=') {
80                                 ret = -EBADMSG;
81                                 goto error;
82                         }
83                         *end = '\0';
84                         name = strstrip(start);
85                         value = strstrip(end + 1);
86                         end = strchr(value, COMMENT);
87                         if (end && *end == COMMENT) {
88                                 *end = '\0';
89                                 value = strstrip(value);
90                         }
91
92                         result.section = section;
93                         result.name = name;
94                         result.value = value;
95                         /* callback with parse result */
96                         ret = cb(&result, user_data);
97                         if (ret < 0) {
98                                 ret = -EBADMSG;
99                                 goto error;
100                         }
101                 }
102         }
103         return 0;
104
105 error:
106         if (f)
107                 fclose(f);
108         _E("Failed to read %s:%d!", file_name, lineno);
109         return ret;
110 }
111
112 static int config_table_lookup(void *table,
113                                const char *section,
114                                const char *lvalue,
115                                ConfigParserCallback *func,
116                                int *ltype,
117                                void **data)
118 {
119         ConfigTableItem *t;
120
121         assert(table);
122         assert(lvalue);
123         assert(func);
124         assert(ltype);
125         assert(data);
126
127         for (t = table; t->lvalue; t++) {
128
129                 if (!streq(lvalue, t->lvalue))
130                         continue;
131
132                 if (!streq_ptr(section, t->section))
133                         continue;
134
135                 *func = t->cb;
136                 *ltype = t->ltype;
137                 *data = t->data;
138                 return 1;
139         }
140
141         return 0;
142 }
143
144 /* Run the user supplied parser for an assignment */
145 static int config_parse_table(const char *filename,
146                               unsigned line,
147                               void *table,
148                               const char *section,
149                               const char *lvalue,
150                               const char *rvalue)
151 {
152         ConfigParserCallback cb = NULL;
153         int ltype = 0;
154         void *data = NULL;
155         int r;
156
157         assert(filename);
158         assert(section);
159         assert(lvalue);
160         assert(rvalue);
161
162         r = config_table_lookup(table,
163                                 section,
164                                 lvalue,
165                                 &cb,
166                                 &ltype,
167                                 &data);
168         if (r <= 0)
169                 return r;
170
171         if (cb)
172                 return cb(filename,
173                           line,
174                           section,
175                           lvalue,
176                           ltype,
177                           rvalue,
178                           data);
179
180         return 0;
181 }
182
183 int config_parse_new(const char *filename, void *table)
184 {
185         _cleanup_fclose_ FILE *f = NULL;
186         char *sections[MAX_SECTION] = { 0 };
187         char *section = NULL, *n, *e, l[LINE_MAX];
188         size_t len;
189         int i, r, num_section = 0;
190         bool already;
191         unsigned line = 0;
192
193         assert(filename);
194
195         f = fopen(filename, "r");
196         if (!f) {
197                 const int saved_errno = errno;
198                 _E("Failed to open file %s", filename); // can modify errno
199                 return -saved_errno;
200         }
201
202         while (!feof(f)) {
203                 _cleanup_free_ char *lvalue = NULL, *rvalue = NULL;
204                 char *rs = NULL;
205
206                 if (fgets(l, LINE_MAX, f) == NULL) {
207                         if (feof(f))
208                                 break;
209
210                         _E("Failed to parse configuration file '%s': %m", filename);
211                         r = -errno;
212                         goto finish;
213                 }
214
215                 line++;
216                 truncate_nl(l);
217
218                 if (strchr(COMMENTS NEWLINE, *l))
219                         continue;
220
221                 if (*l == '[') {
222                         len = strlen(l);
223                         if (l[len-1] != ']') {
224                                 _E("Error: Invalid section header: %s", l);
225                                 r = -EBADMSG;
226                                 goto finish;
227                         }
228
229                         n = strndup(l+1, len-2);
230                         if (!n) {
231                                 r = -ENOMEM;
232                                 goto finish;
233                         }
234
235                         already = false;
236                         for (i = 0; i < num_section; i++) {
237                                 if (streq(n, sections[i])) {
238                                         section = sections[i];
239                                         already = true;
240                                         free(n);
241                                         break;
242                                 }
243                         }
244
245                         if (already)
246                                 continue;
247
248                         section = n;
249                         sections[num_section] = n;
250                         num_section++;
251                         if (num_section > MAX_SECTION) {
252                                 _E("Error: max number of section reached: %d", num_section);
253                                 r = -EOVERFLOW;
254                                 goto finish;
255                         }
256
257                         continue;
258                 }
259
260                 if (!section)
261                         continue;
262
263                 e = strchr(l, '=');
264                 if (e == NULL) {
265                         _D("Warning: config: no '=' character in line '%s'.", l);
266                         continue;
267                 }
268
269                 lvalue = strndup(l, e-l);
270                 if (!lvalue) {
271                         r = -ENOMEM;
272                         goto finish;
273                 }
274
275                 strstrip(lvalue);
276
277                 rs = strstrip(e+1);
278                 rvalue = strdup(rs);
279                 if (!rvalue) {
280                         r = -ENOMEM;
281                         goto finish;
282                 }
283
284                 strstrip(rvalue);
285
286                 r = config_parse_table(filename,
287                                        line,
288                                        table,
289                                        section,
290                                        lvalue,
291                                        rvalue);
292                 if (r < 0)
293                         goto finish;
294         }
295
296         r = 0;
297
298 finish:
299         for (i = 0; i < num_section; i++)
300                 if (sections[i])
301                         free(sections[i]);
302
303         return r;
304 }
305
306 int config_parse_dir(const char *dir, ConfigParseFunc fp, void *data)
307 {
308         _cleanup_closedir_ DIR *d = NULL;
309         struct dirent *de;
310
311         d = opendir(dir);
312         if (!d) {
313                 _E("Failed to open dir: %s", dir);
314                 return errno;
315         }
316
317         for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) {
318                 if (!de) {
319                         if (errno > 0)
320                                 return -errno;
321                         break;
322                 } else if (streq(de->d_name, ".") || streq(de->d_name, "..")) {
323                         continue;
324                 }
325
326                 _cleanup_free_ char *path = NULL;
327                 int r;
328
329                 if (de->d_type != DT_REG)
330                         continue;
331
332                 r = asprintf(&path, "%s/%s", dir, de->d_name);
333                 if (r < 0)
334                         return -ENOMEM;
335
336                 r = fp(path, data);
337                 /* Do not just break loop until parse all file of
338                  * dir. Just only put log */
339                 if (r < 0)
340                         _D("Failed to parse config: %s", de->d_name);
341         }
342
343         return 0;
344 }
345
346 int config_parse_bool(const char *filename,
347                       unsigned line,
348                       const char *section,
349                       const char *lvalue,
350                       int ltype,
351                       const char *rvalue,
352                       void *data)
353 {
354         int k;
355         bool *b = data;
356
357         assert(filename);
358         assert(lvalue);
359         assert(rvalue);
360         assert(data);
361
362         k = parse_boolean(rvalue);
363         if (k < 0) {
364                 _E("Failed to parse boolean value, ignoring: %s", rvalue);
365                 return 0;
366         }
367
368         *b = !!k;
369
370         return 0;
371 }
372
373 #define DEFINE_PARSER(type, vartype, conv_func)          \
374         int config_parse_##type(                                        \
375                                 const char *filename,                   \
376                                 unsigned line,                          \
377                                 const char *section,                    \
378                                 const char *lvalue,                     \
379                                 int ltype,                              \
380                                 const char *rvalue,                     \
381                                 void *data) {                           \
382                                                                                                                 \
383                 vartype *i = data;                                      \
384                                                                         \
385                 assert(filename);                                       \
386                 assert(lvalue);                                         \
387                 assert(rvalue);                                         \
388                 assert(data);                                           \
389                                                                         \
390                 *i = conv_func(rvalue);                          \
391                 return 0;                                               \
392                 }
393
394 DEFINE_PARSER(int, int, atoi)
395 DEFINE_PARSER(float, float, atof)
396 DEFINE_PARSER(long, long, atol)
397
398 int config_parse_string(const char *filename,
399                         unsigned line,
400                         const char *section,
401                         const char *lvalue,
402                         int ltype,
403                         const char *rvalue,
404                         void *data)
405 {
406         char **s = data, *n;
407
408         assert(filename);
409         assert(lvalue);
410         assert(rvalue);
411         assert(data);
412
413         if (is_empty(rvalue))
414                 n = NULL;
415         else {
416                 n = strdup(rvalue);
417                 if (!n)
418                         return -ENOMEM;
419         }
420
421         free(*s);
422         *s = n;
423
424         return 0;
425 }
426
427 int config_parse_bytes(const char *filename,
428                        unsigned line,
429                        const char *section,
430                        const char *lvalue,
431                        int ltype,
432                        const char *rvalue,
433                        void *data)
434 {
435         size_t *s = data;
436         int r;
437
438         assert(filename);
439         assert(lvalue);
440         assert(rvalue);
441         assert(data);
442
443         if (is_empty(rvalue))
444                 *s = 0;
445         else {
446                 r = parse_bytes(rvalue, s);
447                 if (r < 0)
448                         return r;
449         }
450
451         return 0;
452 }
453
454 int config_parse_strv(const char *filename,
455                       unsigned line,
456                       const char *section,
457                       const char *lvalue,
458                       int ltype,
459                       const char *rvalue,
460                       void *data)
461 {
462         char ***strv = data;
463         char **o = NULL, **v = NULL, **vv = NULL;
464         int r;
465
466         assert(filename);
467         assert(lvalue);
468         assert(rvalue);
469         assert(data);
470
471         if (is_empty(rvalue))
472                 return 0;
473
474         r = str_to_strv(rvalue, &v, WHITESPACE);
475         if (r < 0)
476                 return r;
477
478         o = *strv;
479
480         r = strv_attach(o, v, &vv, true);
481         if (r < 0)
482                 return r;
483
484         *strv = vv;
485
486         return 0;
487 }