<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>