libmultipath: resource leak in read_value_block()
[multipath-tools/.git] / libmultipath / parser.c
1 /*
2  * Part:        Configuration file parser/reader. Place into the dynamic
3  *              data structure representation the conf file
4  *
5  * Version:     $Id: parser.c,v 1.0.3 2003/05/11 02:28:03 acassen Exp $
6  *
7  * Author:      Alexandre Cassen, <acassen@linux-vs.org>
8  *
9  *              This program is distributed in the hope that it will be useful,
10  *              but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *              See the GNU General Public License for more details.
13  *
14  *              This program is free software; you can redistribute it and/or
15  *              modify it under the terms of the GNU General Public License
16  *              as published by the Free Software Foundation; either version
17  *              2 of the License, or (at your option) any later version.
18  */
19
20 #include <syslog.h>
21
22 #include "parser.h"
23 #include "memory.h"
24 #include "debug.h"
25
26 /* local vars */
27 static int sublevel = 0;
28 static vector keywords = NULL;
29 static vector *keywords_addr = NULL;
30 static int line_nr;
31
32 void set_current_keywords (vector *k)
33 {
34         keywords_addr = k;
35         keywords = NULL;
36 }
37
38 int
39 keyword_alloc(vector keywords, char *string, int (*handler) (vector),
40                 int (*print) (char *, int, void *), int unique)
41 {
42         struct keyword *keyword;
43
44         keyword = (struct keyword *) MALLOC(sizeof (struct keyword));
45
46         if (!keyword)
47                 return 1;
48
49         if (!vector_alloc_slot(keywords)) {
50                 FREE(keyword);
51                 return 1;
52         }
53         keyword->string = string;
54         keyword->handler = handler;
55         keyword->print = print;
56         keyword->unique = unique;
57
58         vector_set_slot(keywords, keyword);
59
60         return 0;
61 }
62
63 int
64 install_keyword_root(char *string, int (*handler) (vector))
65 {
66         int r = keyword_alloc(keywords, string, handler, NULL, 1);
67         if (!r)
68                 *keywords_addr = keywords;
69         return r;
70 }
71
72 void
73 install_sublevel(void)
74 {
75         sublevel++;
76 }
77
78 void
79 install_sublevel_end(void)
80 {
81         sublevel--;
82 }
83
84 int
85 _install_keyword(char *string, int (*handler) (vector),
86                 int (*print) (char *, int, void *), int unique)
87 {
88         int i = 0;
89         struct keyword *keyword;
90
91         /* fetch last keyword */
92         keyword = VECTOR_SLOT(keywords, VECTOR_SIZE(keywords) - 1);
93
94         /* position to last sub level */
95         for (i = 0; i < sublevel; i++)
96                 keyword =
97                     VECTOR_SLOT(keyword->sub, VECTOR_SIZE(keyword->sub) - 1);
98
99         /* First sub level allocation */
100         if (!keyword->sub)
101                 keyword->sub = vector_alloc();
102
103         if (!keyword->sub)
104                 return 1;
105
106         /* add new sub keyword */
107         return keyword_alloc(keyword->sub, string, handler, print, unique);
108 }
109
110 void
111 free_keywords(vector keywords)
112 {
113         struct keyword *keyword;
114         int i;
115
116         if (!keywords)
117                 return;
118
119         for (i = 0; i < VECTOR_SIZE(keywords); i++) {
120                 keyword = VECTOR_SLOT(keywords, i);
121                 if (keyword->sub)
122                         free_keywords(keyword->sub);
123                 FREE(keyword);
124         }
125         vector_free(keywords);
126 }
127
128 struct keyword *
129 find_keyword(vector v, char * name)
130 {
131         struct keyword *keyword;
132         int i;
133         int len;
134
135         if (!name || !keywords)
136                 return NULL;
137
138         if (!v)
139                 v = keywords;
140
141         len = strlen(name);
142
143         for (i = 0; i < VECTOR_SIZE(v); i++) {
144                 keyword = VECTOR_SLOT(v, i);
145                 if ((strlen(keyword->string) == len) &&
146                     !strcmp(keyword->string, name))
147                         return keyword;
148                 if (keyword->sub) {
149                         keyword = find_keyword(keyword->sub, name);
150                         if (keyword)
151                                 return keyword;
152                 }
153         }
154         return NULL;
155 }
156
157 int
158 snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, void *data)
159 {
160         int r;
161         int fwd = 0;
162         char *f = fmt;
163
164         if (!kw || !kw->print)
165                 return 0;
166
167         do {
168                 if (fwd == len || *f == '\0')
169                         break;
170                 if (*f != '%') {
171                         *(buff + fwd) = *f;
172                         fwd++;
173                         continue;
174                 }
175                 f++;
176                 switch(*f) {
177                 case 'k':
178                         fwd += snprintf(buff + fwd, len - fwd, "%s", kw->string);
179                         break;
180                 case 'v':
181                         r = kw->print(buff + fwd, len - fwd, data);
182                         if (!r) { /* no output if no value */
183                                 buff = '\0';
184                                 return 0;
185                         }
186                         fwd += r;
187                         break;
188                 }
189                 if (fwd > len)
190                         fwd = len;
191         } while (*f++);
192         return fwd;
193 }
194
195 vector
196 alloc_strvec(char *string)
197 {
198         char *cp, *start, *token;
199         int strlen;
200         int in_string;
201         vector strvec;
202
203         if (!string)
204                 return NULL;
205
206         cp = string;
207
208         /* Skip white spaces */
209         while ((isspace((int) *cp) || !isascii((int) *cp)) && *cp != '\0')
210                 cp++;
211
212         /* Return if there is only white spaces */
213         if (*cp == '\0')
214                 return NULL;
215
216         /* Return if string begin with a comment */
217         if (*cp == '!' || *cp == '#')
218                 return NULL;
219
220         /* Create a vector and alloc each command piece */
221         strvec = vector_alloc();
222
223         if (!strvec)
224                 return NULL;
225
226         in_string = 0;
227         while (1) {
228                 if (!vector_alloc_slot(strvec))
229                         goto out;
230
231                 start = cp;
232                 if (*cp == '"') {
233                         cp++;
234                         token = MALLOC(2);
235
236                         if (!token)
237                                 goto out;
238
239                         *(token) = '"';
240                         *(token + 1) = '\0';
241                         if (in_string)
242                                 in_string = 0;
243                         else
244                                 in_string = 1;
245                 } else if (!in_string && (*cp == '{' || *cp == '}')) {
246                         token = MALLOC(2);
247
248                         if (!token)
249                                 goto out;
250
251                         *(token) = *cp;
252                         *(token + 1) = '\0';
253                         cp++;
254                 } else {
255                         while ((in_string ||
256                                 (!isspace((int) *cp) && isascii((int) *cp) &&
257                                  *cp != '!' && *cp != '#' && *cp != '{' &&
258                                  *cp != '}')) && *cp != '\0' && *cp != '"')
259                                 cp++;
260                         strlen = cp - start;
261                         token = MALLOC(strlen + 1);
262
263                         if (!token)
264                                 goto out;
265
266                         memcpy(token, start, strlen);
267                         *(token + strlen) = '\0';
268                 }
269                 vector_set_slot(strvec, token);
270
271                 while ((isspace((int) *cp) || !isascii((int) *cp))
272                        && *cp != '\0')
273                         cp++;
274                 if (*cp == '\0' || *cp == '!' || *cp == '#')
275                         return strvec;
276         }
277 out:
278         vector_free(strvec);
279         return NULL;
280 }
281
282 int
283 read_line(char *buf, int size)
284 {
285         int ch;
286         int count = 0;
287
288         while ((ch = fgetc(stream)) != EOF && (int) ch != '\n'
289                && (int) ch != '\r') {
290                 if (count < size)
291                         buf[count] = (int) ch;
292                 else
293                         break;
294                 count++;
295         }
296         return (ch == EOF) ? 0 : 1;
297 }
298
299 vector
300 read_value_block(void)
301 {
302         char *buf;
303         int i;
304         char *str = NULL;
305         char *dup;
306         vector vec = NULL;
307         vector elements = vector_alloc();
308
309         if (!elements)
310                 return NULL;
311
312         buf = (char *) MALLOC(MAXBUF);
313
314         if (!buf) {
315                 vector_free(elements);
316                 return NULL;
317         }
318
319         while (read_line(buf, MAXBUF)) {
320                 vec = alloc_strvec(buf);
321                 if (vec) {
322                         str = VECTOR_SLOT(vec, 0);
323                         if (!strcmp(str, EOB)) {
324                                 free_strvec(vec);
325                                 break;
326                         }
327
328                         for (i = 0; i < VECTOR_SIZE(vec); i++) {
329                                 str = VECTOR_SLOT(vec, i);
330                                 dup = (char *) MALLOC(strlen(str) + 1);
331                                 if (!dup)
332                                         goto out;
333                                 memcpy(dup, str, strlen(str));
334
335                                 if (!vector_alloc_slot(elements)) {
336                                         free_strvec(vec);
337                                         goto out1;
338                                 }
339
340                                 vector_set_slot(elements, dup);
341                         }
342                         free_strvec(vec);
343                 }
344                 memset(buf, 0, MAXBUF);
345         }
346         FREE(buf);
347         return elements;
348 out1:
349         FREE(dup);
350 out:
351         FREE(buf);
352         vector_free(elements);
353         return NULL;
354 }
355
356 int
357 alloc_value_block(vector strvec, void (*alloc_func) (vector))
358 {
359         char *buf;
360         char *str = NULL;
361         vector vec = NULL;
362
363         buf = (char *) MALLOC(MAXBUF);
364
365         if (!buf)
366                 return 1;
367
368         while (read_line(buf, MAXBUF)) {
369                 vec = alloc_strvec(buf);
370                 if (vec) {
371                         str = VECTOR_SLOT(vec, 0);
372                         if (!strcmp(str, EOB)) {
373                                 free_strvec(vec);
374                                 break;
375                         }
376
377                         if (VECTOR_SIZE(vec))
378                                 (*alloc_func) (vec);
379
380                         free_strvec(vec);
381                 }
382                 memset(buf, 0, MAXBUF);
383         }
384         FREE(buf);
385         return 0;
386 }
387
388 void *
389 set_value(vector strvec)
390 {
391         char *str = VECTOR_SLOT(strvec, 1);
392         size_t size;
393         int i = 0;
394         int len = 0;
395         char *alloc = NULL;
396         char *tmp;
397
398         if (!str)
399                 return NULL;
400
401         size = strlen(str);
402         if (size == 0)
403                 return NULL;
404
405         if (*str == '"') {
406                 for (i = 2; i < VECTOR_SIZE(strvec); i++) {
407                         str = VECTOR_SLOT(strvec, i);
408                         len += strlen(str);
409                         if (!alloc)
410                                 alloc =
411                                     (char *) MALLOC(sizeof (char *) *
412                                                     (len + 1));
413                         else {
414                                 alloc =
415                                     REALLOC(alloc, sizeof (char *) * (len + 1));
416                                 tmp = VECTOR_SLOT(strvec, i-1);
417                                 if (alloc && *str != '"' && *tmp != '"')
418                                         strncat(alloc, " ", 1);
419                         }
420
421                         if (alloc && i != VECTOR_SIZE(strvec)-1)
422                                 strncat(alloc, str, strlen(str));
423                 }
424         } else {
425                 alloc = MALLOC(sizeof (char *) * (size + 1));
426                 if (alloc)
427                         memcpy(alloc, str, size);
428         }
429         return alloc;
430 }
431
432 /* non-recursive configuration stream handler */
433 static int kw_level = 0;
434
435 int warn_on_duplicates(vector uniques, char *str)
436 {
437         char *tmp;
438         int i;
439
440         vector_foreach_slot(uniques, tmp, i) {
441                 if (!strcmp(str, tmp)) {
442                         condlog(1, "multipath.conf line %d, duplicate keyword: %s", line_nr, str);
443                         return 0;
444                 }
445         }
446         tmp = strdup(str);
447         if (!tmp)
448                 return 1;
449         if (!vector_alloc_slot(uniques)) {
450                 free(tmp);
451                 return 1;
452         }
453         vector_set_slot(uniques, tmp);
454         return 0;
455 }
456
457 void free_uniques(vector uniques)
458 {
459         char *tmp;
460         int i;
461
462         vector_foreach_slot(uniques, tmp, i)
463                 free(tmp);
464         vector_free(uniques);
465 }
466
467 int
468 process_stream(vector keywords)
469 {
470         int i;
471         int r = 0;
472         struct keyword *keyword;
473         char *str;
474         char *buf;
475         vector strvec;
476         vector uniques;
477
478         uniques = vector_alloc();
479         if (!uniques)
480                 return 1;
481
482         buf = MALLOC(MAXBUF);
483
484         if (!buf) {
485                 vector_free(uniques);
486                 return 1;
487         }
488
489         while (read_line(buf, MAXBUF)) {
490                 line_nr++;
491                 strvec = alloc_strvec(buf);
492                 memset(buf,0, MAXBUF);
493
494                 if (!strvec)
495                         continue;
496
497                 str = VECTOR_SLOT(strvec, 0);
498
499                 if (!strcmp(str, EOB) && kw_level > 0) {
500                         free_strvec(strvec);
501                         break;
502                 }
503
504                 for (i = 0; i < VECTOR_SIZE(keywords); i++) {
505                         keyword = VECTOR_SLOT(keywords, i);
506
507                         if (!strcmp(keyword->string, str)) {
508                                 if (keyword->unique &&
509                                     warn_on_duplicates(uniques, str)) {
510                                                 r = 1;
511                                                 free_strvec(strvec);
512                                                 goto out;
513                                 }
514                                 if (keyword->handler)
515                                         r += (*keyword->handler) (strvec);
516
517                                 if (keyword->sub) {
518                                         kw_level++;
519                                         r += process_stream(keyword->sub);
520                                         kw_level--;
521                                 }
522                                 break;
523                         }
524                 }
525                 if (i >= VECTOR_SIZE(keywords))
526                         condlog(1, "multipath.conf +%d, invalid keyword: %s",
527                                 line_nr, str);
528
529                 free_strvec(strvec);
530         }
531
532 out:
533         FREE(buf);
534         free_uniques(uniques);
535         return r;
536 }
537
538 int alloc_keywords(void)
539 {
540         if (!keywords)
541                 keywords = vector_alloc();
542
543         if (!keywords)
544                 return 1;
545
546         return 0;
547 }
548
549 /* Data initialization */
550 int
551 init_data(char *conf_file, void (*init_keywords) (void))
552 {
553         int r;
554
555         stream = fopen(conf_file, "r");
556         if (!stream) {
557                 syslog(LOG_WARNING, "Configuration file open problem");
558                 return 1;
559         }
560
561         /* Init Keywords structure */
562         (*init_keywords) ();
563
564 /* Dump configuration *
565   vector_dump(keywords);
566   dump_keywords(keywords, 0);
567 */
568
569         /* Stream handling */
570         line_nr = 0;
571         r = process_stream(keywords);
572         fclose(stream);
573         //free_keywords(keywords);
574
575         return r;
576 }