]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: cfgparse/bind: suggest correct spelling for unknown bind keywords
authorWilly Tarreau <w@1wt.eu>
Fri, 12 Mar 2021 09:14:07 +0000 (10:14 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 12 Mar 2021 13:13:21 +0000 (14:13 +0100)
Just like with the server keywords, now's the turn of "bind" keywords.
The difference is that 100% of the bind keywords are registered, thus
we do not need the list of extra keywords.

There are multiple bind line parsers today, all were updated:
  - peers
  - log
  - dgram-bind
  - cli

$ printf "listen f\nbind :8000 tcut\n" | ./haproxy -c -f /dev/stdin
[NOTICE] 070/101358 (25146) : haproxy version is 2.4-dev11-7b8787-26
[NOTICE] 070/101358 (25146) : path to executable is ./haproxy
[ALERT] 070/101358 (25146) : parsing [/dev/stdin:2] : 'bind :8000' unknown keyword 'tcut'; did you mean 'tcp-ut' maybe ?
[ALERT] 070/101358 (25146) : Error(s) found in configuration file : /dev/stdin
[ALERT] 070/101358 (25146) : Fatal errors found in configuration.

include/haproxy/listener.h
src/cfgparse-listen.c
src/cfgparse.c
src/cli.c
src/listener.c
src/log.c

index ee02b0cc2b60c3315035eb9203274aef0934e363..e4cea50fc6a5f0d6bd957f09cf65ec999506ec55 100644 (file)
@@ -167,6 +167,7 @@ struct bind_kw *bind_find_kw(const char *kw);
 
 /* Dumps all registered "bind" keywords to the <out> string pointer. */
 void bind_dump_kws(char **out);
+const char *bind_find_best_kw(const char *word);
 
 void bind_recount_thread_bits(struct bind_conf *conf);
 unsigned int bind_map_thread_id(const struct bind_conf *conf, unsigned int r);
index b60741aed036939201591b7d391333ec95c290c4..ac5002536abbe0f20c01cdedf3d402659488a9b3 100644 (file)
@@ -389,9 +389,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
 
                cur_arg = 2;
                while (*(args[cur_arg])) {
-                       static int bind_dumped;
                        struct bind_kw *kw;
-                       char *err;
+                       const char *best;
 
                        kw = bind_find_kw(args[cur_arg]);
                        if (kw) {
@@ -431,17 +430,13 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
                                continue;
                        }
 
-                       err = NULL;
-                       if (!bind_dumped) {
-                               bind_dump_kws(&err);
-                               indent_msg(&err, 4);
-                               bind_dumped = 1;
-                       }
-
-                       ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'.%s%s\n",
-                                file, linenum, args[0], args[1], args[cur_arg],
-                                err ? " Registered keywords :" : "", err ? err : "");
-                       free(err);
+                       best = bind_find_best_kw(args[cur_arg]);
+                       if (best)
+                               ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'; did you mean '%s' maybe ?\n",
+                                        file, linenum, args[0], args[1], args[cur_arg], best);
+                       else
+                               ha_alert("parsing [%s:%d] : '%s %s' unknown keyword '%s'.\n",
+                                        file, linenum, args[0], args[1], args[cur_arg]);
 
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
index 9c8efa2f6cd6f46c0fd38ab1d8be061a3e2408d9..269b47d0b5629fa0dbec2c81af232472a6069524 100644 (file)
@@ -609,7 +609,6 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm)
 
        if (strcmp(args[0], "bind") == 0 || strcmp(args[0], "default-bind") == 0) {
                int cur_arg;
-               static int kws_dumped;
                struct bind_conf *bind_conf;
                struct bind_kw *kw;
 
@@ -689,17 +688,13 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm)
                        cur_arg += 1 + kw->skip;
                }
                if (*args[cur_arg] != 0) {
-                       char *kws = NULL;
-
-                       if (!kws_dumped) {
-                               kws_dumped = 1;
-                               bind_dump_kws(&kws);
-                               indent_msg(&kws, 4);
-                       }
-                       ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section.%s%s\n",
-                                file, linenum, args[cur_arg], cursection,
-                                kws ? " Registered keywords :" : "", kws ? kws: "");
-                       free(kws);
+                       const char *best = bind_find_best_kw(args[cur_arg]);
+                       if (best)
+                               ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section; did you mean '%s' maybe ?\n",
+                                        file, linenum, args[cur_arg], cursection, best);
+                       else
+                               ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section.\n",
+                                        file, linenum, args[cur_arg], cursection);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
index 72919ce320da6a1d5c618ab3a591f9ff9d9ead7d..04c4e7a1962bdcdc70cd12bc62c607ec376ddae0 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -290,8 +290,8 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
 
                cur_arg = 3;
                while (*args[cur_arg]) {
-                       static int bind_dumped;
                        struct bind_kw *kw;
+                       const char *best;
 
                        kw = bind_find_kw(args[cur_arg]);
                        if (kw) {
@@ -314,15 +314,13 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
                                continue;
                        }
 
-                       if (!bind_dumped) {
-                               bind_dump_kws(err);
-                               indent_msg(err, 4);
-                               bind_dumped = 1;
-                       }
-
-                       memprintf(err, "'%s %s' : unknown keyword '%s'.%s%s",
-                                 args[0], args[1], args[cur_arg],
-                                 err && *err ? " Registered keywords :" : "", err && *err ? *err : "");
+                       best = bind_find_best_kw(args[cur_arg]);
+                       if (best)
+                               memprintf(err, "'%s %s' : unknown keyword '%s'. Did you mean '%s' maybe ?",
+                                         args[0], args[1], args[cur_arg], best);
+                       else
+                               memprintf(err, "'%s %s' : unknown keyword '%s'.",
+                                         args[0], args[1], args[cur_arg]);
                        return -1;
                }
 
@@ -2656,8 +2654,8 @@ int mworker_cli_proxy_new_listener(char *line)
        cur_arg = 1;
 
        while (*args[cur_arg]) {
-                       static int bind_dumped;
                        struct bind_kw *kw;
+                       const char *best;
 
                        kw = bind_find_kw(args[cur_arg]);
                        if (kw) {
@@ -2680,15 +2678,13 @@ int mworker_cli_proxy_new_listener(char *line)
                                continue;
                        }
 
-                       if (!bind_dumped) {
-                               bind_dump_kws(&err);
-                               indent_msg(&err, 4);
-                               bind_dumped = 1;
-                       }
-
-                       memprintf(&err, "'%s %s' : unknown keyword '%s'.%s%s",
-                                 args[0], args[1], args[cur_arg],
-                                 err ? " Registered keywords :" : "", err ? err : "");
+                       best = bind_find_best_kw(args[cur_arg]);
+                       if (best)
+                               memprintf(&err, "'%s %s' : unknown keyword '%s'. Did you mean '%s' maybe ?",
+                                         args[0], args[1], args[cur_arg], best);
+                       else
+                               memprintf(&err, "'%s %s' : unknown keyword '%s'.",
+                                         args[0], args[1], args[cur_arg]);
                        goto err;
        }
 
index 4dfaa7f23e525b396310ad6e2c070cf6d7b9174f..882d17fbe32712df13b4336692e86d929070d7fa 100644 (file)
@@ -1261,6 +1261,37 @@ void bind_dump_kws(char **out)
        }
 }
 
+/* Try to find in srv_keyword the word that looks closest to <word> by counting
+ * transitions between letters, digits and other characters. Will return the
+ * best matching word if found, otherwise NULL.
+ */
+const char *bind_find_best_kw(const char *word)
+{
+       uint8_t word_sig[1024];
+       uint8_t list_sig[1024];
+       const struct bind_kw_list *kwl;
+       const char *best_ptr = NULL;
+       int dist, best_dist = INT_MAX;
+       int index;
+
+       make_word_fingerprint(word_sig, word);
+       list_for_each_entry(kwl, &bind_keywords.list, list) {
+               for (index = 0; kwl->kw[index].kw != NULL; index++) {
+                       make_word_fingerprint(list_sig, kwl->kw[index].kw);
+                       dist = word_fingerprint_distance(word_sig, list_sig);
+                       if (dist < best_dist) {
+                               best_dist = dist;
+                               best_ptr = kwl->kw[index].kw;
+                       }
+               }
+       }
+
+       if (best_dist > 2 * strlen(word) || (best_ptr && best_dist > 2 * strlen(best_ptr)))
+               best_ptr = NULL;
+
+       return best_ptr;
+}
+
 /************************************************************************/
 /*      All supported sample and ACL keywords must be declared here.    */
 /************************************************************************/
index 2bf7f15805cd162e7e611f605ecca512abe6468a..c7712182374e22fa7d049fc5973dda3a5fda519d 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -3894,7 +3894,6 @@ int cfg_parse_log_forward(const char *file, int linenum, char **args, int kwm)
        }
        else if (strcmp(args[0], "bind") == 0) {
                int cur_arg;
-               static int kws_dumped;
                struct bind_conf *bind_conf;
                struct bind_kw *kw;
                struct listener *l;
@@ -3949,24 +3948,19 @@ int cfg_parse_log_forward(const char *file, int linenum, char **args, int kwm)
                        cur_arg += 1 + kw->skip;
                }
                if (*args[cur_arg] != 0) {
-                       char *kws = NULL;
-
-                       if (!kws_dumped) {
-                               kws_dumped = 1;
-                               bind_dump_kws(&kws);
-                               indent_msg(&kws, 4);
-                       }
-                       ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section.%s%s\n",
-                                file, linenum, args[cur_arg], cursection,
-                                kws ? " Registered keywords :" : "", kws ? kws: "");
-                       free(kws);
+                       const char *best = bind_find_best_kw(args[cur_arg]);
+                       if (best)
+                               ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section; did you mean '%s' maybe ?\n",
+                                        file, linenum, args[cur_arg], cursection, best);
+                       else
+                               ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section.\n",
+                                        file, linenum, args[cur_arg], cursection);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
        }
        else if (strcmp(args[0], "dgram-bind") == 0) {
                int cur_arg;
-               static int kws_dumped;
                struct bind_conf *bind_conf;
                struct bind_kw *kw;
                struct listener *l;
@@ -4015,17 +4009,13 @@ int cfg_parse_log_forward(const char *file, int linenum, char **args, int kwm)
                        cur_arg += 1 + kw->skip;
                }
                if (*args[cur_arg] != 0) {
-                       char *kws = NULL;
-
-                       if (!kws_dumped) {
-                               kws_dumped = 1;
-                               bind_dump_kws(&kws);
-                               indent_msg(&kws, 4);
-                       }
-                       ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section.%s%s\n",
-                                file, linenum, args[cur_arg], cursection,
-                                kws ? " Registered keywords :" : "", kws ? kws: "");
-                       free(kws);
+                       const char *best = bind_find_best_kw(args[cur_arg]);
+                       if (best)
+                               ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section; did you mean '%s' maybe ?\n",
+                                        file, linenum, args[cur_arg], cursection, best);
+                       else
+                               ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section.\n",
+                                        file, linenum, args[cur_arg], cursection);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }