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.
30 static int sublevel = 0;
34 keyword_alloc(vector keywords, char *string,
35 int (*handler) (struct config *, vector),
36 int (*print) (struct config *, char *, int, const void*),
39 struct keyword *keyword;
41 keyword = (struct keyword *) MALLOC(sizeof (struct keyword));
46 if (!vector_alloc_slot(keywords)) {
50 keyword->string = string;
51 keyword->handler = handler;
52 keyword->print = print;
53 keyword->unique = unique;
55 vector_set_slot(keywords, keyword);
61 install_sublevel(void)
67 install_sublevel_end(void)
73 _install_keyword(vector keywords, char *string,
74 int (*handler) (struct config *, vector),
75 int (*print) (struct config *, char *, int, const void*),
79 struct keyword *keyword;
81 /* fetch last keyword */
82 keyword = VECTOR_SLOT(keywords, VECTOR_SIZE(keywords) - 1);
84 /* position to last sub level */
85 for (i = 0; i < sublevel; i++)
87 VECTOR_SLOT(keyword->sub, VECTOR_SIZE(keyword->sub) - 1);
89 /* First sub level allocation */
91 keyword->sub = vector_alloc();
96 /* add new sub keyword */
97 return keyword_alloc(keyword->sub, string, handler, print, unique);
101 free_keywords(vector keywords)
103 struct keyword *keyword;
109 for (i = 0; i < VECTOR_SIZE(keywords); i++) {
110 keyword = VECTOR_SLOT(keywords, i);
112 free_keywords(keyword->sub);
115 vector_free(keywords);
119 find_keyword(vector keywords, vector v, char * name)
121 struct keyword *keyword;
125 if (!name || !keywords)
133 for (i = 0; i < VECTOR_SIZE(v); i++) {
134 keyword = VECTOR_SLOT(v, i);
135 if ((strlen(keyword->string) == len) &&
136 !strcmp(keyword->string, name))
139 keyword = find_keyword(keywords, keyword->sub, name);
148 snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
156 if (!kw || !kw->print)
160 if (fwd == len || *f == '\0')
170 fwd += snprintf(buff + fwd, len - fwd, "%s", kw->string);
173 conf = get_multipath_config();
174 r = kw->print(conf, buff + fwd, len - fwd, data);
175 put_multipath_config(conf);
176 if (!r) { /* no output if no value */
190 alloc_strvec(char *string)
192 char *cp, *start, *token;
202 /* Skip white spaces */
203 while ((isspace((int) *cp) || !isascii((int) *cp)) && *cp != '\0')
206 /* Return if there is only white spaces */
210 /* Return if string begin with a comment */
211 if (*cp == '!' || *cp == '#')
214 /* Create a vector and alloc each command piece */
215 strvec = vector_alloc();
222 if (!vector_alloc_slot(strvec))
239 } else if (!in_string && (*cp == '{' || *cp == '}')) {
250 (!isspace((int) *cp) && isascii((int) *cp) &&
251 *cp != '!' && *cp != '#' && *cp != '{' &&
252 *cp != '}')) && *cp != '\0' && *cp != '"')
255 token = MALLOC(strlen + 1);
260 memcpy(token, start, strlen);
261 *(token + strlen) = '\0';
263 vector_set_slot(strvec, token);
265 while ((isspace((int) *cp) || !isascii((int) *cp))
268 if (*cp == '\0' || *cp == '!' || *cp == '#')
277 read_line(FILE *stream, char *buf, int size)
281 if (fgets(buf, size, stream) == NULL)
283 strtok_r(buf, "\n\r", &p);
288 set_value(vector strvec)
290 char *str = VECTOR_SLOT(strvec, 1);
298 condlog(0, "option '%s' missing value",
299 (char *)VECTOR_SLOT(strvec, 0));
304 condlog(0, "option '%s' has empty value",
305 (char *)VECTOR_SLOT(strvec, 0));
309 alloc = MALLOC(sizeof (char) * (size + 1));
311 memcpy(alloc, str, size);
313 condlog(0, "can't allocate memeory for option '%s'",
314 (char *)VECTOR_SLOT(strvec, 0));
317 /* Even empty quotes counts as a value (An empty string) */
318 alloc = (char *) MALLOC(sizeof (char));
320 condlog(0, "can't allocate memeory for option '%s'",
321 (char *)VECTOR_SLOT(strvec, 0));
324 for (i = 2; i < VECTOR_SIZE(strvec); i++) {
325 str = VECTOR_SLOT(strvec, i);
328 condlog(0, "parse error for option '%s'",
329 (char *)VECTOR_SLOT(strvec, 0));
335 /* The first +1 is for the NULL byte. The rest are for the
336 * spaces between words */
337 len += strlen(str) + 1;
338 alloc = REALLOC(alloc, sizeof (char) * len);
341 condlog(0, "can't allocate memeory for option '%s'",
342 (char *)VECTOR_SLOT(strvec, 0));
346 strncat(alloc, " ", 1);
347 strncat(alloc, str, strlen(str));
352 /* non-recursive configuration stream handler */
353 static int kw_level = 0;
355 int warn_on_duplicates(vector uniques, char *str, char *file)
360 vector_foreach_slot(uniques, tmp, i) {
361 if (!strcmp(str, tmp)) {
362 condlog(1, "%s line %d, duplicate keyword: %s",
370 if (!vector_alloc_slot(uniques)) {
374 vector_set_slot(uniques, tmp);
378 void free_uniques(vector uniques)
383 vector_foreach_slot(uniques, tmp, i)
385 vector_free(uniques);
389 is_sublevel_keyword(char *str)
391 return (strcmp(str, "defaults") == 0 || strcmp(str, "blacklist") == 0 ||
392 strcmp(str, "blacklist_exceptions") == 0 ||
393 strcmp(str, "devices") == 0 || strcmp(str, "devices") == 0 ||
394 strcmp(str, "device") == 0 || strcmp(str, "multipaths") == 0 ||
395 strcmp(str, "multipath") == 0);
399 validate_config_strvec(vector strvec, char *file)
404 str = VECTOR_SLOT(strvec, 0);
406 condlog(0, "can't parse option on line %d of %s",
411 if (VECTOR_SIZE(strvec) > 1)
412 condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 1), line_nr, file);
416 condlog(0, "invalid keyword '%s' on line %d of %s",
420 if (is_sublevel_keyword(str)) {
421 str = VECTOR_SLOT(strvec, 1);
423 condlog(0, "missing '{' on line %d of %s",
425 else if (*str != '{')
426 condlog(0, "expecting '{' on line %d of %s. found '%s'",
428 else if (VECTOR_SIZE(strvec) > 2)
429 condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
432 str = VECTOR_SLOT(strvec, 1);
434 condlog(0, "missing value for option '%s' on line %d of %s",
435 (char *)VECTOR_SLOT(strvec, 0), line_nr, file);
439 if (VECTOR_SIZE(strvec) > 2)
440 condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
443 for (i = 2; i < VECTOR_SIZE(strvec); i++) {
444 str = VECTOR_SLOT(strvec, i);
446 condlog(0, "can't parse value on line %d of %s",
451 if (VECTOR_SIZE(strvec) > i + 1)
452 condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr, file);
456 condlog(0, "missing closing quotes on line %d of %s",
462 process_stream(struct config *conf, FILE *stream, vector keywords, char *file)
466 struct keyword *keyword;
472 uniques = vector_alloc();
476 buf = MALLOC(MAXBUF);
479 vector_free(uniques);
483 while (read_line(stream, buf, MAXBUF)) {
485 strvec = alloc_strvec(buf);
489 if (validate_config_strvec(strvec, file) != 0) {
494 str = VECTOR_SLOT(strvec, 0);
496 if (!strcmp(str, EOB)) {
501 condlog(0, "unmatched '%s' at line %d of %s",
505 for (i = 0; i < VECTOR_SIZE(keywords); i++) {
506 keyword = VECTOR_SLOT(keywords, i);
508 if (!strcmp(keyword->string, str)) {
509 if (keyword->unique &&
510 warn_on_duplicates(uniques, str, file)) {
515 if (keyword->handler) {
516 t = (*keyword->handler) (conf, strvec);
519 condlog(1, "multipath.conf +%d, parsing failed: %s",
525 r += process_stream(conf, stream,
532 if (i >= VECTOR_SIZE(keywords))
533 condlog(1, "%s line %d, invalid keyword: %s",
541 free_uniques(uniques);
545 /* Data initialization */
547 process_file(struct config *conf, char *file)
552 if (!conf->keywords) {
553 condlog(0, "No keywords alocated");
556 stream = fopen(file, "r");
558 condlog(0, "couldn't open configuration file '%s': %s",
559 file, strerror(errno));
563 /* Stream handling */
565 r = process_stream(conf, stream, conf->keywords, file);
567 //free_keywords(keywords);