From c0ff6794814943e5483fdcea51ee8b806fd94c81 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 12 Mar 2021 09:14:19 +0100 Subject: [PATCH] MINOR: cfgparse: suggest correct spelling for unknown words in proxy sections Let's start by the largest keyword list, the listeners. Many keywords were still not part of a list, so a common_kw_list array was added to list the not enumerated ones. Now for example, typing "tmout" properly suggests "timeout": $ printf "frontend f\ntmout client 10s\n" | ./haproxy -c -f /dev/stdin [NOTICE] 070/091355 (22545) : haproxy version is 2.4-dev11-3b728a-21 [NOTICE] 070/091355 (22545) : path to executable is ./haproxy [ALERT] 070/091355 (22545) : parsing [/dev/stdin:2] : unknown keyword 'tmout' in 'frontend' section; did you mean 'timeout' maybe ? [ALERT] 070/091355 (22545) : Error(s) found in configuration file : /dev/stdin [ALERT] 070/091355 (22545) : Fatal errors found in configuration. --- src/cfgparse-listen.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 1a39c2f75..b60741aed 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -33,6 +33,26 @@ #include #include +/* some keywords that are still being parsed using strcmp() and are not + * registered anywhere. They are used as suggestions for mistyped words. + */ +static const char *common_kw_list[] = { + "listen", "frontend", "backend", "defaults", "server", + "default-server", "server-template", "bind", "monitor-net", + "monitor-uri", "mode", "id", "description", "disabled", "enabled", + "bind-process", "acl", "dynamic-cookie-key", "cookie", "email-alert", + "persist", "appsession", "load-server-state-from-file", + "server-state-file-name", "max-session-srv-conns", "capture", + "retries", "http-request", "http-response", "http-after-response", + "http-send-name-header", "block", "redirect", "use_backend", + "use-server", "force-persist", "ignore-persist", "force-persist", + "stick-table", "stick", "stats", "option", "default_backend", + "http-reuse", "monitor", "transparent", "maxconn", "backlog", + "fullconn", "grace", "dispatch", "balance", "hash-type", + "hash-balance-factor", "unique-id-format", "unique-id-header", + "log-format", "log-format-sd", "log-tag", "log", "source", "usesrc", + NULL /* must be last */ +}; /* Report a warning if a rule is placed after a 'tcp-request session' rule. * Return 1 if the warning has been emitted, otherwise 0. @@ -2917,6 +2937,7 @@ stats_error_parsing: } else { struct cfg_kw_list *kwl; + const char *best; int index; list_for_each_entry(kwl, &cfg_keywords.list, list) { @@ -2941,7 +2962,11 @@ stats_error_parsing: } } - ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection); + best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_LISTEN, common_kw_list); + if (best) + ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section; did you mean '%s' maybe ?\n", file, linenum, args[0], cursection, best); + else + ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], cursection); err_code |= ERR_ALERT | ERR_FATAL; goto out; }