2 * Part: Configuration file parser/reader. Place into the dynamic
3 * data structure representation the conf file
5 * Version: $Id: parser.c,v 1.0.3 2003/05/11 02:28:03 acassen Exp $
7 * Author: Alexandre Cassen, <acassen@linux-vs.org>
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.
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.
28 static int sublevel = 0;
29 static vector keywords = NULL;
30 static vector *keywords_addr = NULL;
33 void set_current_keywords (vector *k)
40 keyword_alloc(vector keywords, char *string, int (*handler) (vector),
41 int (*print) (char *, int, void *), int unique)
43 struct keyword *keyword;
45 keyword = (struct keyword *) MALLOC(sizeof (struct keyword));
50 if (!vector_alloc_slot(keywords)) {
54 keyword->string = string;
55 keyword->handler = handler;
56 keyword->print = print;
57 keyword->unique = unique;
59 vector_set_slot(keywords, keyword);
65 install_keyword_root(char *string, int (*handler) (vector))
67 int r = keyword_alloc(keywords, string, handler, NULL, 1);
69 *keywords_addr = keywords;
74 install_sublevel(void)
80 install_sublevel_end(void)
86 _install_keyword(char *string, int (*handler) (vector),
87 int (*print) (char *, int, void *), int unique)
90 struct keyword *keyword;
92 /* fetch last keyword */
93 keyword = VECTOR_SLOT(keywords, VECTOR_SIZE(keywords) - 1);
95 /* position to last sub level */
96 for (i = 0; i < sublevel; i++)
98 VECTOR_SLOT(keyword->sub, VECTOR_SIZE(keyword->sub) - 1);
100 /* First sub level allocation */
102 keyword->sub = vector_alloc();
107 /* add new sub keyword */
108 return keyword_alloc(keyword->sub, string, handler, print, unique);
112 free_keywords(vector keywords)
114 struct keyword *keyword;
120 for (i = 0; i < VECTOR_SIZE(keywords); i++) {
121 keyword = VECTOR_SLOT(keywords, i);
123 free_keywords(keyword->sub);
126 vector_free(keywords);
130 find_keyword(vector v, char * name)
132 struct keyword *keyword;
136 if (!name || !keywords)
144 for (i = 0; i < VECTOR_SIZE(v); i++) {
145 keyword = VECTOR_SLOT(v, i);
146 if ((strlen(keyword->string) == len) &&
147 !strcmp(keyword->string, name))
150 keyword = find_keyword(keyword->sub, name);
159 snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, void *data)
165 if (!kw || !kw->print)
169 if (fwd == len || *f == '\0')
179 fwd += snprintf(buff + fwd, len - fwd, "%s", kw->string);
182 r = kw->print(buff + fwd, len - fwd, data);
183 if (!r) { /* no output if no value */
197 alloc_strvec(char *string)
199 char *cp, *start, *token;
209 /* Skip white spaces */
210 while ((isspace((int) *cp) || !isascii((int) *cp)) && *cp != '\0')
213 /* Return if there is only white spaces */
217 /* Return if string begin with a comment */
218 if (*cp == '!' || *cp == '#')
221 /* Create a vector and alloc each command piece */
222 strvec = vector_alloc();
229 if (!vector_alloc_slot(strvec))
246 } else if (!in_string && (*cp == '{' || *cp == '}')) {
257 (!isspace((int) *cp) && isascii((int) *cp) &&
258 *cp != '!' && *cp != '#' && *cp != '{' &&
259 *cp != '}')) && *cp != '\0' && *cp != '"')
262 token = MALLOC(strlen + 1);
267 memcpy(token, start, strlen);
268 *(token + strlen) = '\0';
270 vector_set_slot(strvec, token);
272 while ((isspace((int) *cp) || !isascii((int) *cp))
275 if (*cp == '\0' || *cp == '!' || *cp == '#')
284 read_line(FILE *stream, char *buf, int size)
288 if (fgets(buf, size, stream) == NULL)
290 strtok_r(buf, "\n\r", &p);
295 set_value(vector strvec)
297 char *str = VECTOR_SLOT(strvec, 1);
305 condlog(0, "option '%s' missing value",
306 (char *)VECTOR_SLOT(strvec, 0));
311 condlog(0, "option '%s' has empty value",
312 (char *)VECTOR_SLOT(strvec, 0));
316 alloc = MALLOC(sizeof (char) * (size + 1));
318 memcpy(alloc, str, size);
320 condlog(0, "can't allocate memeory for option '%s'",
321 (char *)VECTOR_SLOT(strvec, 0));
324 /* Even empty quotes counts as a value (An empty string) */
325 alloc = (char *) MALLOC(sizeof (char));
327 condlog(0, "can't allocate memeory for option '%s'",
328 (char *)VECTOR_SLOT(strvec, 0));
331 for (i = 2; i < VECTOR_SIZE(strvec); i++) {
332 str = VECTOR_SLOT(strvec, i);
335 condlog(0, "parse error for option '%s'",
336 (char *)VECTOR_SLOT(strvec, 0));
342 /* The first +1 is for the NULL byte. The rest are for the
343 * spaces between words */
344 len += strlen(str) + 1;
345 alloc = REALLOC(alloc, sizeof (char) * len);
348 condlog(0, "can't allocate memeory for option '%s'",
349 (char *)VECTOR_SLOT(strvec, 0));
353 strncat(alloc, " ", 1);
354 strncat(alloc, str, strlen(str));
359 /* non-recursive configuration stream handler */
360 static int kw_level = 0;
362 int warn_on_duplicates(vector uniques, char *str, char *file)
367 vector_foreach_slot(uniques, tmp, i) {
368 if (!strcmp(str, tmp)) {
369 condlog(1, "%s line %d, duplicate keyword: %s",
377 if (!vector_alloc_slot(uniques)) {
381 vector_set_slot(uniques, tmp);
385 void free_uniques(vector uniques)
390 vector_foreach_slot(uniques, tmp, i)
392 vector_free(uniques);
396 is_sublevel_keyword(char *str)
398 return (strcmp(str, "defaults") == 0 || strcmp(str, "blacklist") == 0 ||
399 strcmp(str, "blacklist_exceptions") == 0 ||
400 strcmp(str, "devices") == 0 || strcmp(str, "devices") == 0 ||
401 strcmp(str, "device") == 0 || strcmp(str, "multipaths") == 0 ||
402 strcmp(str, "multipath") == 0);
406 validate_config_strvec(vector strvec, char *file)
411 str = VECTOR_SLOT(strvec, 0);
413 condlog(0, "can't parse option on line %d of %s",
418 if (VECTOR_SIZE(strvec) > 1)
419 condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 1), line_nr, file);
423 condlog(0, "invalid keyword '%s' on line %d of %s",
427 if (is_sublevel_keyword(str)) {
428 str = VECTOR_SLOT(strvec, 1);
430 condlog(0, "missing '{' on line %d of %s",
432 else if (*str != '{')
433 condlog(0, "expecting '{' on line %d of %s. found '%s'",
435 else if (VECTOR_SIZE(strvec) > 2)
436 condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
439 str = VECTOR_SLOT(strvec, 1);
441 condlog(0, "missing value for option '%s' on line %d of %s",
442 (char *)VECTOR_SLOT(strvec, 0), line_nr, file);
446 if (VECTOR_SIZE(strvec) > 2)
447 condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
450 for (i = 2; i < VECTOR_SIZE(strvec); i++) {
451 str = VECTOR_SLOT(strvec, i);
453 condlog(0, "can't parse value on line %d of %s",
458 if (VECTOR_SIZE(strvec) > i + 1)
459 condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr, file);
463 condlog(0, "missing closing quotes on line %d of %s",
469 process_stream(FILE *stream, vector keywords, char *file)
473 struct keyword *keyword;
479 uniques = vector_alloc();
483 buf = MALLOC(MAXBUF);
486 vector_free(uniques);
490 while (read_line(stream, buf, MAXBUF)) {
492 strvec = alloc_strvec(buf);
496 if (validate_config_strvec(strvec, file) != 0) {
501 str = VECTOR_SLOT(strvec, 0);
503 if (!strcmp(str, EOB)) {
508 condlog(0, "unmatched '%s' at line %d of %s",
512 for (i = 0; i < VECTOR_SIZE(keywords); i++) {
513 keyword = VECTOR_SLOT(keywords, i);
515 if (!strcmp(keyword->string, str)) {
516 if (keyword->unique &&
517 warn_on_duplicates(uniques, str, file)) {
522 if (keyword->handler) {
523 t = (*keyword->handler) (strvec);
526 condlog(1, "multipath.conf +%d, parsing failed: %s",
532 r += process_stream(stream,
539 if (i >= VECTOR_SIZE(keywords))
540 condlog(1, "%s line %d, invalid keyword: %s",
548 free_uniques(uniques);
552 int alloc_keywords(void)
555 keywords = vector_alloc();
563 /* Data initialization */
565 process_file(char *file)
571 condlog(0, "No keywords alocated");
574 stream = fopen(file, "r");
576 condlog(0, "couldn't open configuration file '%s': %s",
577 file, strerror(errno));
581 /* Stream handling */
583 r = process_stream(stream, keywords, file);
585 //free_keywords(keywords);