libmultipath: resource leak in read_value_block()
[multipath-tools/.git] / libmultipath / parser.c
index ebb14cd..526c45b 100644 (file)
@@ -1,11 +1,11 @@
-/* 
+/*
  * Part:        Configuration file parser/reader. Place into the dynamic
  *              data structure representation the conf file
- *  
+ *
  * Version:     $Id: parser.c,v 1.0.3 2003/05/11 02:28:03 acassen Exp $
- * 
+ *
  * Author:      Alexandre Cassen, <acassen@linux-vs.org>
- *              
+ *
  *              This program is distributed in the hope that it will be useful,
  *              but WITHOUT ANY WARRANTY; without even the implied warranty of
  *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 #include "parser.h"
 #include "memory.h"
+#include "debug.h"
 
 /* local vars */
 static int sublevel = 0;
+static vector keywords = NULL;
+static vector *keywords_addr = NULL;
+static int line_nr;
+
+void set_current_keywords (vector *k)
+{
+       keywords_addr = k;
+       keywords = NULL;
+}
 
 int
-keyword_alloc(vector keywords, char *string, int (*handler) (vector))
+keyword_alloc(vector keywords, char *string, int (*handler) (vector),
+               int (*print) (char *, int, void *), int unique)
 {
        struct keyword *keyword;
 
@@ -34,13 +45,15 @@ keyword_alloc(vector keywords, char *string, int (*handler) (vector))
 
        if (!keyword)
                return 1;
-       
+
        if (!vector_alloc_slot(keywords)) {
                FREE(keyword);
                return 1;
        }
        keyword->string = string;
        keyword->handler = handler;
+       keyword->print = print;
+       keyword->unique = unique;
 
        vector_set_slot(keywords, keyword);
 
@@ -50,7 +63,10 @@ keyword_alloc(vector keywords, char *string, int (*handler) (vector))
 int
 install_keyword_root(char *string, int (*handler) (vector))
 {
-       return keyword_alloc(keywords, string, handler);
+       int r = keyword_alloc(keywords, string, handler, NULL, 1);
+       if (!r)
+               *keywords_addr = keywords;
+       return r;
 }
 
 void
@@ -66,7 +82,8 @@ install_sublevel_end(void)
 }
 
 int
-install_keyword(char *string, int (*handler) (vector))
+_install_keyword(char *string, int (*handler) (vector),
+               int (*print) (char *, int, void *), int unique)
 {
        int i = 0;
        struct keyword *keyword;
@@ -87,7 +104,7 @@ install_keyword(char *string, int (*handler) (vector))
                return 1;
 
        /* add new sub keyword */
-       return keyword_alloc(keyword->sub, string, handler);
+       return keyword_alloc(keyword->sub, string, handler, print, unique);
 }
 
 void
@@ -96,6 +113,9 @@ free_keywords(vector keywords)
        struct keyword *keyword;
        int i;
 
+       if (!keywords)
+               return;
+
        for (i = 0; i < VECTOR_SIZE(keywords); i++) {
                keyword = VECTOR_SLOT(keywords, i);
                if (keyword->sub)
@@ -105,6 +125,73 @@ free_keywords(vector keywords)
        vector_free(keywords);
 }
 
+struct keyword *
+find_keyword(vector v, char * name)
+{
+       struct keyword *keyword;
+       int i;
+       int len;
+
+       if (!name || !keywords)
+               return NULL;
+
+       if (!v)
+               v = keywords;
+
+       len = strlen(name);
+
+       for (i = 0; i < VECTOR_SIZE(v); i++) {
+               keyword = VECTOR_SLOT(v, i);
+               if ((strlen(keyword->string) == len) &&
+                   !strcmp(keyword->string, name))
+                       return keyword;
+               if (keyword->sub) {
+                       keyword = find_keyword(keyword->sub, name);
+                       if (keyword)
+                               return keyword;
+               }
+       }
+       return NULL;
+}
+
+int
+snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, void *data)
+{
+       int r;
+       int fwd = 0;
+       char *f = fmt;
+
+       if (!kw || !kw->print)
+               return 0;
+
+       do {
+               if (fwd == len || *f == '\0')
+                       break;
+               if (*f != '%') {
+                       *(buff + fwd) = *f;
+                       fwd++;
+                       continue;
+               }
+               f++;
+               switch(*f) {
+               case 'k':
+                       fwd += snprintf(buff + fwd, len - fwd, "%s", kw->string);
+                       break;
+               case 'v':
+                       r = kw->print(buff + fwd, len - fwd, data);
+                       if (!r) { /* no output if no value */
+                               buff = '\0';
+                               return 0;
+                       }
+                       fwd += r;
+                       break;
+               }
+               if (fwd > len)
+                       fwd = len;
+       } while (*f++);
+       return fwd;
+}
+
 vector
 alloc_strvec(char *string)
 {
@@ -119,7 +206,7 @@ alloc_strvec(char *string)
        cp = string;
 
        /* Skip white spaces */
-       while (isspace((int) *cp) && *cp != '\0')
+       while ((isspace((int) *cp) || !isascii((int) *cp)) && *cp != '\0')
                cp++;
 
        /* Return if there is only white spaces */
@@ -155,10 +242,20 @@ alloc_strvec(char *string)
                                in_string = 0;
                        else
                                in_string = 1;
+               } else if (!in_string && (*cp == '{' || *cp == '}')) {
+                       token = MALLOC(2);
+
+                       if (!token)
+                               goto out;
 
+                       *(token) = *cp;
+                       *(token + 1) = '\0';
+                       cp++;
                } else {
-                       while ((in_string || !isspace((int) *cp)) && *cp
-                               != '\0' && *cp != '"')
+                       while ((in_string ||
+                               (!isspace((int) *cp) && isascii((int) *cp) &&
+                                *cp != '!' && *cp != '#' && *cp != '{' &&
+                                *cp != '}')) && *cp != '\0' && *cp != '"')
                                cp++;
                        strlen = cp - start;
                        token = MALLOC(strlen + 1);
@@ -171,7 +268,8 @@ alloc_strvec(char *string)
                }
                vector_set_slot(strvec, token);
 
-               while (isspace((int) *cp) && *cp != '\0')
+               while ((isspace((int) *cp) || !isascii((int) *cp))
+                      && *cp != '\0')
                        cp++;
                if (*cp == '\0' || *cp == '!' || *cp == '#')
                        return strvec;
@@ -208,13 +306,15 @@ read_value_block(void)
        vector vec = NULL;
        vector elements = vector_alloc();
 
+       if (!elements)
+               return NULL;
+
        buf = (char *) MALLOC(MAXBUF);
 
-       if (!buf)
+       if (!buf) {
+               vector_free(elements);
                return NULL;
-
-       if (!elements)
-               goto out;
+       }
 
        while (read_line(buf, MAXBUF)) {
                vec = alloc_strvec(buf);
@@ -225,17 +325,20 @@ read_value_block(void)
                                break;
                        }
 
-                       if (VECTOR_SIZE(vec))
-                               for (i = 0; i < VECTOR_SIZE(vec); i++) {
-                                       str = VECTOR_SLOT(vec, i);
-                                       dup = (char *) MALLOC(strlen(str) + 1);
-                                       memcpy(dup, str, strlen(str));
-
-                                       if (!vector_alloc_slot(elements))
-                                               goto out1;
+                       for (i = 0; i < VECTOR_SIZE(vec); i++) {
+                               str = VECTOR_SLOT(vec, i);
+                               dup = (char *) MALLOC(strlen(str) + 1);
+                               if (!dup)
+                                       goto out;
+                               memcpy(dup, str, strlen(str));
 
-                                       vector_set_slot(elements, dup);
+                               if (!vector_alloc_slot(elements)) {
+                                       free_strvec(vec);
+                                       goto out1;
                                }
+
+                               vector_set_slot(elements, dup);
+                       }
                        free_strvec(vec);
                }
                memset(buf, 0, MAXBUF);
@@ -246,6 +349,7 @@ out1:
        FREE(dup);
 out:
        FREE(buf);
+       vector_free(elements);
        return NULL;
 }
 
@@ -285,12 +389,19 @@ void *
 set_value(vector strvec)
 {
        char *str = VECTOR_SLOT(strvec, 1);
-       int size = strlen(str);
+       size_t size;
        int i = 0;
        int len = 0;
        char *alloc = NULL;
        char *tmp;
 
+       if (!str)
+               return NULL;
+
+       size = strlen(str);
+       if (size == 0)
+               return NULL;
+
        if (*str == '"') {
                for (i = 2; i < VECTOR_SIZE(strvec); i++) {
                        str = VECTOR_SLOT(strvec, i);
@@ -303,22 +414,56 @@ set_value(vector strvec)
                                alloc =
                                    REALLOC(alloc, sizeof (char *) * (len + 1));
                                tmp = VECTOR_SLOT(strvec, i-1);
-                               if (*str != '"' && *tmp != '"')
+                               if (alloc && *str != '"' && *tmp != '"')
                                        strncat(alloc, " ", 1);
                        }
 
-                       if (i != VECTOR_SIZE(strvec)-1)
+                       if (alloc && i != VECTOR_SIZE(strvec)-1)
                                strncat(alloc, str, strlen(str));
                }
        } else {
                alloc = MALLOC(sizeof (char *) * (size + 1));
-               memcpy(alloc, str, size);
+               if (alloc)
+                       memcpy(alloc, str, size);
        }
        return alloc;
 }
 
 /* non-recursive configuration stream handler */
 static int kw_level = 0;
+
+int warn_on_duplicates(vector uniques, char *str)
+{
+       char *tmp;
+       int i;
+
+       vector_foreach_slot(uniques, tmp, i) {
+               if (!strcmp(str, tmp)) {
+                       condlog(1, "multipath.conf line %d, duplicate keyword: %s", line_nr, str);
+                       return 0;
+               }
+       }
+       tmp = strdup(str);
+       if (!tmp)
+               return 1;
+       if (!vector_alloc_slot(uniques)) {
+               free(tmp);
+               return 1;
+       }
+       vector_set_slot(uniques, tmp);
+       return 0;
+}
+
+void free_uniques(vector uniques)
+{
+       char *tmp;
+       int i;
+
+       vector_foreach_slot(uniques, tmp, i)
+               free(tmp);
+       vector_free(uniques);
+}
+
 int
 process_stream(vector keywords)
 {
@@ -328,13 +473,21 @@ process_stream(vector keywords)
        char *str;
        char *buf;
        vector strvec;
+       vector uniques;
+
+       uniques = vector_alloc();
+       if (!uniques)
+               return 1;
 
        buf = MALLOC(MAXBUF);
 
-       if (!buf)
+       if (!buf) {
+               vector_free(uniques);
                return 1;
+       }
 
        while (read_line(buf, MAXBUF)) {
+               line_nr++;
                strvec = alloc_strvec(buf);
                memset(buf,0, MAXBUF);
 
@@ -352,6 +505,12 @@ process_stream(vector keywords)
                        keyword = VECTOR_SLOT(keywords, i);
 
                        if (!strcmp(keyword->string, str)) {
+                               if (keyword->unique &&
+                                   warn_on_duplicates(uniques, str)) {
+                                               r = 1;
+                                               free_strvec(strvec);
+                                               goto out;
+                               }
                                if (keyword->handler)
                                        r += (*keyword->handler) (strvec);
 
@@ -363,17 +522,33 @@ process_stream(vector keywords)
                                break;
                        }
                }
-               
+               if (i >= VECTOR_SIZE(keywords))
+                       condlog(1, "multipath.conf +%d, invalid keyword: %s",
+                               line_nr, str);
+
                free_strvec(strvec);
        }
 
+out:
        FREE(buf);
+       free_uniques(uniques);
        return r;
 }
 
+int alloc_keywords(void)
+{
+       if (!keywords)
+               keywords = vector_alloc();
+
+       if (!keywords)
+               return 1;
+
+       return 0;
+}
+
 /* Data initialization */
 int
-init_data(char *conf_file, vector (*init_keywords) (void))
+init_data(char *conf_file, void (*init_keywords) (void))
 {
        int r;
 
@@ -392,9 +567,10 @@ init_data(char *conf_file, vector (*init_keywords) (void))
 */
 
        /* Stream handling */
+       line_nr = 0;
        r = process_stream(keywords);
        fclose(stream);
-       free_keywords(keywords);
+       //free_keywords(keywords);
 
        return r;
 }