<div dir="ltr">Applied,<div>Thanks.</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Jun 30, 2014 at 7:14 AM, Benjamin Marzinski <span dir="ltr"><<a href="mailto:bmarzins@redhat.com" target="_blank">bmarzins@redhat.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">multipath's parser for multipath.conf is neither very verbose or forgiving<br>
about errors.  This patch improves both.  multipath will now warn about<br>
obviously missing quotes and curly braces, but will still do the right thing.<br>
It will also give more verbose error messages including a line number when<br>
it can't parse a line.<br>
<br>
Signed-off-by: Benjamin Marzinski <<a href="mailto:bmarzins@redhat.com">bmarzins@redhat.com</a>><br>
---<br>
 libmultipath/parser.c | 152 +++++++++++++++++++++++++++++++++++++++++---------<br>
 1 file changed, 125 insertions(+), 27 deletions(-)<br>
<br>
diff --git a/libmultipath/parser.c b/libmultipath/parser.c<br>
index 0d4c870..accff62 100644<br>
--- a/libmultipath/parser.c<br>
+++ b/libmultipath/parser.c<br>
@@ -395,36 +395,57 @@ set_value(vector strvec)<br>
        char *alloc = NULL;<br>
        char *tmp;<br>
<br>
-       if (!str)<br>
+       if (!str) {<br>
+               condlog(0, "option '%s' missing value",<br>
+                       (char *)VECTOR_SLOT(strvec, 0));<br>
                return NULL;<br>
-<br>
+       }<br>
        size = strlen(str);<br>
-       if (size == 0)<br>
+       if (size == 0) {<br>
+               condlog(0, "option '%s' has empty value",<br>
+                       (char *)VECTOR_SLOT(strvec, 0));<br>
                return NULL;<br>
-<br>
-       if (*str == '"') {<br>
-               for (i = 2; i < VECTOR_SIZE(strvec); i++) {<br>
-                       str = VECTOR_SLOT(strvec, i);<br>
-                       len += strlen(str);<br>
-                       if (!alloc)<br>
-                               alloc =<br>
-                                   (char *) MALLOC(sizeof (char) *<br>
-                                                   (len + 1));<br>
-                       else {<br>
-                               alloc =<br>
-                                   REALLOC(alloc, sizeof (char) * (len + 1));<br>
-                               tmp = VECTOR_SLOT(strvec, i-1);<br>
-                               if (alloc && *str != '"' && *tmp != '"')<br>
-                                       strncat(alloc, " ", 1);<br>
-                       }<br>
-<br>
-                       if (alloc && i != VECTOR_SIZE(strvec)-1)<br>
-                               strncat(alloc, str, strlen(str));<br>
-               }<br>
-       } else {<br>
+       }<br>
+       if (*str != '"') {<br>
                alloc = MALLOC(sizeof (char) * (size + 1));<br>
                if (alloc)<br>
                        memcpy(alloc, str, size);<br>
+               else<br>
+                       condlog(0, "can't allocate memeory for option '%s'",<br>
+                               (char *)VECTOR_SLOT(strvec, 0));<br>
+               return alloc;<br>
+       }<br>
+       /* Even empty quotes counts as a value (An empty string) */<br>
+       alloc = (char *) MALLOC(sizeof (char));<br>
+       if (!alloc) {<br>
+               condlog(0, "can't allocate memeory for option '%s'",<br>
+                       (char *)VECTOR_SLOT(strvec, 0));<br>
+               return NULL;<br>
+       }<br>
+       for (i = 2; i < VECTOR_SIZE(strvec); i++) {<br>
+               str = VECTOR_SLOT(strvec, i);<br>
+               if (!str) {<br>
+                       free(alloc);<br>
+                       condlog(0, "parse error for option '%s'",<br>
+                               (char *)VECTOR_SLOT(strvec, 0));<br>
+                       return NULL;<br>
+               }<br>
+               if (*str == '"')<br>
+                       break;<br>
+               tmp = alloc;<br>
+               /* The first +1 is for the NULL byte. The rest are for the<br>
+                * spaces between words */<br>
+               len += strlen(str) + 1;<br>
+               alloc = REALLOC(alloc, sizeof (char) * len);<br>
+               if (!alloc) {<br>
+                       FREE(tmp);<br>
+                       condlog(0, "can't allocate memeory for option '%s'",<br>
+                               (char *)VECTOR_SLOT(strvec, 0));<br>
+                       return NULL;<br>
+               }<br>
+               if (*alloc != '\0')<br>
+                       strncat(alloc, " ", 1);<br>
+               strncat(alloc, str, strlen(str));<br>
        }<br>
        return alloc;<br>
 }<br>
@@ -465,6 +486,74 @@ void free_uniques(vector uniques)<br>
 }<br>
<br>
 int<br>
+is_sublevel_keyword(char *str)<br>
+{<br>
+       return (strcmp(str, "defaults") == 0 || strcmp(str, "blacklist") == 0 ||<br>
+               strcmp(str, "blacklist_exceptions") == 0 ||<br>
+               strcmp(str, "devices") == 0 || strcmp(str, "devices") == 0 ||<br>
+               strcmp(str, "device") == 0 || strcmp(str, "multipaths") == 0 ||<br>
+               strcmp(str, "multipath") == 0);<br>
+}<br>
+<br>
+int<br>
+validate_config_strvec(vector strvec)<br>
+{<br>
+       char *str;<br>
+       int i;<br>
+<br>
+       str = VECTOR_SLOT(strvec, 0);<br>
+       if (str == NULL) {<br>
+               condlog(0, "can't parse option on line %d of config file",<br>
+                       line_nr);<br>
+       return -1;<br>
+       }<br>
+       if (*str == '}') {<br>
+               if (VECTOR_SIZE(strvec) > 1)<br>
+                       condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 1), line_nr);<br>
+               return 0;<br>
+       }<br>
+       if (*str == '{') {<br>
+               condlog(0, "invalid keyword '%s' on line %d of config file", str, line_nr);<br>
+               return -1;<br>
+       }<br>
+       if (is_sublevel_keyword(str)) {<br>
+               str = VECTOR_SLOT(strvec, 1);<br>
+               if (str == NULL)<br>
+                       condlog(0, "missing '{' on line %d of config file", line_nr);<br>
+               else if (*str != '{')<br>
+                       condlog(0, "expecting '{' on line %d of config file. found '%s'", line_nr, str);<br>
+               else if (VECTOR_SIZE(strvec) > 2)<br>
+                       condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);<br>
+               return 0;<br>
+       }<br>
+       str = VECTOR_SLOT(strvec, 1);<br>
+       if (str == NULL) {<br>
+               condlog(0, "missing value for option '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 0), line_nr);<br>
+               return -1;<br>
+       }<br>
+       if (*str != '"') {<br>
+               if (VECTOR_SIZE(strvec) > 2)<br>
+                       condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, 2), line_nr);<br>
+               return 0;<br>
+       }<br>
+       for (i = 2; i < VECTOR_SIZE(strvec); i++) {<br>
+               str = VECTOR_SLOT(strvec, i);<br>
+               if (str == NULL) {<br>
+                       condlog(0, "can't parse value on line %d of config file", line_nr);<br>
+                       return -1;<br>
+               }<br>
+               if (*str == '"') {<br>
+                       if (VECTOR_SIZE(strvec) > i + 1)<br>
+                               condlog(0, "ignoring extra data starting with '%s' on line %d of config file", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr);<br>
+                       return 0;<br>
+               }<br>
+       }<br>
+       condlog(0, "missing closing quotes on line %d of config file",<br>
+               line_nr);<br>
+       return 0;<br>
+}<br>
+<br>
+int<br>
 process_stream(vector keywords)<br>
 {<br>
        int i;<br>
@@ -494,11 +583,20 @@ process_stream(vector keywords)<br>
                if (!strvec)<br>
                        continue;<br>
<br>
+               if (validate_config_strvec(strvec) != 0) {<br>
+                       free_strvec(strvec);<br>
+                       continue;<br>
+               }<br>
+<br>
                str = VECTOR_SLOT(strvec, 0);<br>
<br>
-               if (!strcmp(str, EOB) && kw_level > 0) {<br>
-                       free_strvec(strvec);<br>
-                       break;<br>
+               if (!strcmp(str, EOB)) {<br>
+                       if (kw_level > 0) {<br>
+                               free_strvec(strvec);<br>
+                               break;<br>
+                       }<br>
+                       condlog(0, "unmatched '%s' at line %d of config file",<br>
+                               EOB, line_nr);<br>
                }<br>
<br>
                for (i = 0; i < VECTOR_SIZE(keywords); i++) {<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.3.1<br>
<br>
</font></span></blockquote></div><br></div>