libmultipath: resource leak in read_value_block()
[multipath-tools/.git] / libmultipath / parser.c
index 6e42590..526c45b 100644 (file)
 
 #include "parser.h"
 #include "memory.h"
+#include "debug.h"
 
 /* local vars */
 static int sublevel = 0;
-vector keywords = NULL;
-vector *keywords_addr = NULL;
+static vector keywords = NULL;
+static vector *keywords_addr = NULL;
+static int line_nr;
 
 void set_current_keywords (vector *k)
 {
@@ -35,7 +37,7 @@ void set_current_keywords (vector *k)
 
 int
 keyword_alloc(vector keywords, char *string, int (*handler) (vector),
-               int (*print) (char *, int, void *))
+               int (*print) (char *, int, void *), int unique)
 {
        struct keyword *keyword;
 
@@ -51,6 +53,7 @@ keyword_alloc(vector keywords, char *string, int (*handler) (vector),
        keyword->string = string;
        keyword->handler = handler;
        keyword->print = print;
+       keyword->unique = unique;
 
        vector_set_slot(keywords, keyword);
 
@@ -60,7 +63,7 @@ keyword_alloc(vector keywords, char *string, int (*handler) (vector),
 int
 install_keyword_root(char *string, int (*handler) (vector))
 {
-       int r = keyword_alloc(keywords, string, handler, NULL);
+       int r = keyword_alloc(keywords, string, handler, NULL, 1);
        if (!r)
                *keywords_addr = keywords;
        return r;
@@ -79,8 +82,8 @@ install_sublevel_end(void)
 }
 
 int
-install_keyword(char *string, int (*handler) (vector),
-               int (*print) (char *, int, void *))
+_install_keyword(char *string, int (*handler) (vector),
+               int (*print) (char *, int, void *), int unique)
 {
        int i = 0;
        struct keyword *keyword;
@@ -101,7 +104,7 @@ install_keyword(char *string, int (*handler) (vector),
                return 1;
 
        /* add new sub keyword */
-       return keyword_alloc(keyword->sub, string, handler, print);
+       return keyword_alloc(keyword->sub, string, handler, print, unique);
 }
 
 void
@@ -303,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);
@@ -320,19 +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)) {
-                                               free_strvec(vec);
-                                               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);
@@ -343,6 +349,7 @@ out1:
        FREE(dup);
 out:
        FREE(buf);
+       vector_free(elements);
        return NULL;
 }
 
@@ -382,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);
@@ -400,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)
 {
@@ -425,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);
 
@@ -449,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);
 
@@ -460,24 +522,36 @@ 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, void (*init_keywords) (void))
 {
        int r;
 
-       if (!keywords)
-               keywords = vector_alloc();
-       if (!keywords)
-               return 1;
        stream = fopen(conf_file, "r");
        if (!stream) {
                syslog(LOG_WARNING, "Configuration file open problem");
@@ -493,6 +567,7 @@ init_data(char *conf_file, void (*init_keywords) (void))
 */
 
        /* Stream handling */
+       line_nr = 0;
        r = process_stream(keywords);
        fclose(stream);
        //free_keywords(keywords);