]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: config: improve .if condition error reporting
authorWilly Tarreau <w@1wt.eu>
Thu, 6 May 2021 13:07:10 +0000 (15:07 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 6 May 2021 15:02:36 +0000 (17:02 +0200)
Let's return the position of the first unparsable character on error,
so that instead of just saying "unparsable conditional expression blah"
we can have:

  [ALERT] 125/150618 (13995) : parsing [test-conds2.cfg:1]: unparsable conditional expression '12/blah' in '.if' at position 1:
    .if 12/blah
        ^
This is important because conditions will be made from environment
variables or later from more complex expressions where the error will
not always be easy to locate.

src/cfgparse.c

index 168cabb73118fb2ed64964eb17251ec99ff35aa1..1d85943fff612eb02eb4d29ae61c28f9a43c81e3 100644 (file)
@@ -1636,9 +1636,10 @@ static int cfg_parse_global_def_path(char **args, int section_type, struct proxy
 
 /* evaluate a condition on a .if/.elif line. The condition is already tokenized
  * in <err>. Returns -1 on error (in which case err is filled with a message,
- * and only in this case), 0 if the condition is false, 1 if it's true.
+ * and only in this case), 0 if the condition is false, 1 if it's true. If
+ * <errptr> is not NULL, it's set to the first invalid character on error.
  */
-static int cfg_eval_condition(char **args, char **err)
+static int cfg_eval_condition(char **args, char **err, const char **errptr)
 {
        char *end;
        long val;
@@ -1650,7 +1651,9 @@ static int cfg_eval_condition(char **args, char **err)
        if (end && *end == '\0')
                return val != 0;
 
-       memprintf(err, "unparsable conditional expression '%s'.\n", args[0]);
+       memprintf(err, "unparsable conditional expression '%s'", args[0]);
+       if (errptr)
+               *errptr = args[0];
        return -1;
 }
 
@@ -1871,6 +1874,7 @@ next_line:
                /* check for config macros */
                if (*args[0] == '.') {
                        if (strcmp(args[0], ".if") == 0) {
+                               const char *errptr = NULL;
                                char *errmsg = NULL;
                                int cond;
 
@@ -1891,9 +1895,14 @@ next_line:
                                        goto next_line;
                                }
 
-                               cond = cfg_eval_condition(args + 1, &errmsg);
+                               cond = cfg_eval_condition(args + 1, &errmsg, &errptr);
                                if (cond < 0) {
-                                       ha_alert("parsing [%s:%d]: %s in '.if'\n", file, linenum, errmsg);
+                                       size_t newpos = sanitize_for_printing(args[1], errptr - args[1], 76);
+
+                                       ha_alert("parsing [%s:%d]: %s in '.if' at position %d:\n  .if %s\n  %*s\n",
+                                                file, linenum, errmsg,
+                                                (int)(errptr-args[1]+1), args[1], (int)(newpos+5), "^");
+
                                        free(errmsg);
                                        err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
                                        goto err;
@@ -1907,6 +1916,7 @@ next_line:
                                goto next_line;
                        }
                        else if (strcmp(args[0], ".elif") == 0) {
+                               const char *errptr = NULL;
                                char *errmsg = NULL;
                                int cond;
 
@@ -1931,9 +1941,14 @@ next_line:
                                        goto next_line;
                                }
 
-                               cond = cfg_eval_condition(args + 1, &errmsg);
+                               cond = cfg_eval_condition(args + 1, &errmsg, &errptr);
                                if (cond < 0) {
-                                       ha_alert("parsing [%s:%d]: %s in '.elif'\n", file, linenum, errmsg);
+                                       size_t newpos = sanitize_for_printing(args[1], errptr - args[1], 74);
+
+                                       ha_alert("parsing [%s:%d]: %s in '.elif' at position %d:\n  .elif %s\n  %*s\n",
+                                                file, linenum, errmsg,
+                                                (int)(errptr-args[1]+1), args[1], (int)(newpos+7), "^");
+
                                        free(errmsg);
                                        err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
                                        goto err;