[multipathd] add "show config" CLI command
[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
25 /* local vars */
26 static int sublevel = 0;
27 vector keywords = NULL;
28
29 int
30 keyword_alloc(vector keywords, char *string, int (*handler) (vector),
31                 int (*print) (char *, int, void *))
32 {
33         struct keyword *keyword;
34
35         keyword = (struct keyword *) MALLOC(sizeof (struct keyword));
36
37         if (!keyword)
38                 return 1;
39         
40         if (!vector_alloc_slot(keywords)) {
41                 FREE(keyword);
42                 return 1;
43         }
44         keyword->string = string;
45         keyword->handler = handler;
46         keyword->print = print;
47
48         vector_set_slot(keywords, keyword);
49
50         return 0;
51 }
52
53 int
54 install_keyword_root(char *string, int (*handler) (vector))
55 {
56         return keyword_alloc(keywords, string, handler, NULL);
57 }
58
59 void
60 install_sublevel(void)
61 {
62         sublevel++;
63 }
64
65 void
66 install_sublevel_end(void)
67 {
68         sublevel--;
69 }
70
71 int
72 install_keyword(char *string, int (*handler) (vector),
73                 int (*print) (char *, int, void *))
74 {
75         int i = 0;
76         struct keyword *keyword;
77
78         /* fetch last keyword */
79         keyword = VECTOR_SLOT(keywords, VECTOR_SIZE(keywords) - 1);
80
81         /* position to last sub level */
82         for (i = 0; i < sublevel; i++)
83                 keyword =
84                     VECTOR_SLOT(keyword->sub, VECTOR_SIZE(keyword->sub) - 1);
85
86         /* First sub level allocation */
87         if (!keyword->sub)
88                 keyword->sub = vector_alloc();
89
90         if (!keyword->sub)
91                 return 1;
92
93         /* add new sub keyword */
94         return keyword_alloc(keyword->sub, string, handler, print);
95 }
96
97 void
98 free_keywords(vector keywords)
99 {
100         struct keyword *keyword;
101         int i;
102
103         for (i = 0; i < VECTOR_SIZE(keywords); i++) {
104                 keyword = VECTOR_SLOT(keywords, i);
105                 if (keyword->sub)
106                         free_keywords(keyword->sub);
107                 FREE(keyword);
108         }
109         vector_free(keywords);
110 }
111
112 struct keyword *
113 find_keyword(vector v, char * name)
114 {
115         struct keyword *keyword;
116         int i;
117         int len;
118
119         if (!name || !keywords)
120                 return NULL;
121
122         if (!v)
123                 v = keywords;
124
125         len = strlen(name);
126
127         for (i = 0; i < VECTOR_SIZE(v); i++) {
128                 keyword = VECTOR_SLOT(v, i);
129                 if ((strlen(keyword->string) == len) &&
130                     !strcmp(keyword->string, name))
131                         return keyword;
132                 if (keyword->sub) {
133                         keyword = find_keyword(keyword->sub, name);
134                         if (keyword)
135                                 return keyword;
136                 }
137         }
138         return NULL;
139 }
140
141 int
142 snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, void *data)
143 {
144         int r;
145         int fwd = 0;
146         char *f = fmt;
147
148         if (!kw || !kw->print)
149                 return 0;
150
151         do {
152                 if (fwd == len || *f == '\0')
153                         break;
154                 if (*f != '%') {
155                         *(buff + fwd) = *f;
156                         fwd++;
157                         continue;
158                 }
159                 f++;
160                 switch(*f) {
161                 case 'k':
162                         fwd += snprintf(buff + fwd, len - fwd, kw->string);
163                         break;
164                 case 'v':
165                         r = kw->print(buff + fwd, len - fwd, data);
166                         if (!r) { /* no output if no value */
167                                 buff = '\0';
168                                 return 0;
169                         }
170                         fwd += r;
171                         break;
172                 }
173                 if (fwd > len)
174                         fwd = len;
175         } while (*f++);
176         return fwd;
177 }
178
179 vector
180 alloc_strvec(char *string)
181 {
182         char *cp, *start, *token;
183         int strlen;
184         int in_string;
185         vector strvec;
186
187         if (!string)
188                 return NULL;
189
190         cp = string;
191
192         /* Skip white spaces */
193         while (isspace((int) *cp) && *cp != '\0')
194                 cp++;
195
196         /* Return if there is only white spaces */
197         if (*cp == '\0')
198                 return NULL;
199
200         /* Return if string begin with a comment */
201         if (*cp == '!' || *cp == '#')
202                 return NULL;
203
204         /* Create a vector and alloc each command piece */
205         strvec = vector_alloc();
206
207         if (!strvec)
208                 return NULL;
209
210         in_string = 0;
211         while (1) {
212                 if (!vector_alloc_slot(strvec))
213                         goto out;
214
215                 start = cp;
216                 if (*cp == '"') {
217                         cp++;
218                         token = MALLOC(2);
219
220                         if (!token)
221                                 goto out;
222
223                         *(token) = '"';
224                         *(token + 1) = '\0';
225                         if (in_string)
226                                 in_string = 0;
227                         else
228                                 in_string = 1;
229
230                 } else {
231                         while ((in_string || !isspace((int) *cp)) && *cp
232                                 != '\0' && *cp != '"')
233                                 cp++;
234                         strlen = cp - start;
235                         token = MALLOC(strlen + 1);
236
237                         if (!token)
238                                 goto out;
239
240                         memcpy(token, start, strlen);
241                         *(token + strlen) = '\0';
242                 }
243                 vector_set_slot(strvec, token);
244
245                 while (isspace((int) *cp) && *cp != '\0')
246                         cp++;
247                 if (*cp == '\0' || *cp == '!' || *cp == '#')
248                         return strvec;
249         }
250 out:
251         vector_free(strvec);
252         return NULL;
253 }
254
255 int
256 read_line(char *buf, int size)
257 {
258         int ch;
259         int count = 0;
260
261         while ((ch = fgetc(stream)) != EOF && (int) ch != '\n'
262                && (int) ch != '\r') {
263                 if (count < size)
264                         buf[count] = (int) ch;
265                 else
266                         break;
267                 count++;
268         }
269         return (ch == EOF) ? 0 : 1;
270 }
271
272 vector
273 read_value_block(void)
274 {
275         char *buf;
276         int i;
277         char *str = NULL;
278         char *dup;
279         vector vec = NULL;
280         vector elements = vector_alloc();
281
282         buf = (char *) MALLOC(MAXBUF);
283
284         if (!buf)
285                 return NULL;
286
287         if (!elements)
288                 goto out;
289
290         while (read_line(buf, MAXBUF)) {
291                 vec = alloc_strvec(buf);
292                 if (vec) {
293                         str = VECTOR_SLOT(vec, 0);
294                         if (!strcmp(str, EOB)) {
295                                 free_strvec(vec);
296                                 break;
297                         }
298
299                         if (VECTOR_SIZE(vec))
300                                 for (i = 0; i < VECTOR_SIZE(vec); i++) {
301                                         str = VECTOR_SLOT(vec, i);
302                                         dup = (char *) MALLOC(strlen(str) + 1);
303                                         memcpy(dup, str, strlen(str));
304
305                                         if (!vector_alloc_slot(elements))
306                                                 goto out1;
307
308                                         vector_set_slot(elements, dup);
309                                 }
310                         free_strvec(vec);
311                 }
312                 memset(buf, 0, MAXBUF);
313         }
314         FREE(buf);
315         return elements;
316 out1:
317         FREE(dup);
318 out:
319         FREE(buf);
320         return NULL;
321 }
322
323 int
324 alloc_value_block(vector strvec, void (*alloc_func) (vector))
325 {
326         char *buf;
327         char *str = NULL;
328         vector vec = NULL;
329
330         buf = (char *) MALLOC(MAXBUF);
331
332         if (!buf)
333                 return 1;
334
335         while (read_line(buf, MAXBUF)) {
336                 vec = alloc_strvec(buf);
337                 if (vec) {
338                         str = VECTOR_SLOT(vec, 0);
339                         if (!strcmp(str, EOB)) {
340                                 free_strvec(vec);
341                                 break;
342                         }
343
344                         if (VECTOR_SIZE(vec))
345                                 (*alloc_func) (vec);
346
347                         free_strvec(vec);
348                 }
349                 memset(buf, 0, MAXBUF);
350         }
351         FREE(buf);
352         return 0;
353 }
354
355 void *
356 set_value(vector strvec)
357 {
358         char *str = VECTOR_SLOT(strvec, 1);
359         int size = strlen(str);
360         int i = 0;
361         int len = 0;
362         char *alloc = NULL;
363         char *tmp;
364
365         if (*str == '"') {
366                 for (i = 2; i < VECTOR_SIZE(strvec); i++) {
367                         str = VECTOR_SLOT(strvec, i);
368                         len += strlen(str);
369                         if (!alloc)
370                                 alloc =
371                                     (char *) MALLOC(sizeof (char *) *
372                                                     (len + 1));
373                         else {
374                                 alloc =
375                                     REALLOC(alloc, sizeof (char *) * (len + 1));
376                                 tmp = VECTOR_SLOT(strvec, i-1);
377                                 if (*str != '"' && *tmp != '"')
378                                         strncat(alloc, " ", 1);
379                         }
380
381                         if (i != VECTOR_SIZE(strvec)-1)
382                                 strncat(alloc, str, strlen(str));
383                 }
384         } else {
385                 alloc = MALLOC(sizeof (char *) * (size + 1));
386                 memcpy(alloc, str, size);
387         }
388         return alloc;
389 }
390
391 /* non-recursive configuration stream handler */
392 static int kw_level = 0;
393 int
394 process_stream(vector keywords)
395 {
396         int i;
397         int r = 0;
398         struct keyword *keyword;
399         char *str;
400         char *buf;
401         vector strvec;
402
403         buf = MALLOC(MAXBUF);
404
405         if (!buf)
406                 return 1;
407
408         while (read_line(buf, MAXBUF)) {
409                 strvec = alloc_strvec(buf);
410                 memset(buf,0, MAXBUF);
411
412                 if (!strvec)
413                         continue;
414
415                 str = VECTOR_SLOT(strvec, 0);
416
417                 if (!strcmp(str, EOB) && kw_level > 0) {
418                         free_strvec(strvec);
419                         break;
420                 }
421
422                 for (i = 0; i < VECTOR_SIZE(keywords); i++) {
423                         keyword = VECTOR_SLOT(keywords, i);
424
425                         if (!strcmp(keyword->string, str)) {
426                                 if (keyword->handler)
427                                         r += (*keyword->handler) (strvec);
428
429                                 if (keyword->sub) {
430                                         kw_level++;
431                                         r += process_stream(keyword->sub);
432                                         kw_level--;
433                                 }
434                                 break;
435                         }
436                 }
437                 
438                 free_strvec(strvec);
439         }
440
441         FREE(buf);
442         return r;
443 }
444
445 /* Data initialization */
446 int
447 init_data(char *conf_file, void (*init_keywords) (void))
448 {
449         int r;
450
451         if (!keywords)
452                 keywords = vector_alloc();
453         if (!keywords)
454                 return 1;
455         stream = fopen(conf_file, "r");
456         if (!stream) {
457                 syslog(LOG_WARNING, "Configuration file open problem");
458                 return 1;
459         }
460
461         /* Init Keywords structure */
462         (*init_keywords) ();
463
464 /* Dump configuration *
465   vector_dump(keywords);
466   dump_keywords(keywords, 0);
467 */
468
469         /* Stream handling */
470         r = process_stream(keywords);
471         fclose(stream);
472         //free_keywords(keywords);
473
474         return r;
475 }