From: Willy Tarreau Date: Thu, 8 Oct 2026 17:31:42 +0000 (+0200) Subject: MINOR: cfgparse: always suggest the section names on an unknown keyword X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=3c60560e1adf2b70b395b2ea269e329fd5a62590;p=haproxy.git MINOR: cfgparse: always suggest the section names on an unknown keyword When an unknown keyword is met in a section, cfg_find_best_match() looks for the closest match among the keywords registered for that section, plus an optional list of extra words passed by the caller, which cfg_parse_global() and cfg_parse_listen() were using to pass a list of a few known hard-coded section names. But this resulted several times in some names not being matched (e.g. "resolvers" which was later added but only for "global"), or others still not being known, e.g. $ printf 'global\n\tcrt-stor\n' | ./haproxy -c -f /dev/stdin [ALERT] : parsing [/dev/stdin:2] : unknown keyword 'crt-stor' in 'global' section; did you mean 'crt-store' maybe ? Let's have the function always consider all known section names since they are always permitted, that is much more effective and will no longer require to hard-code certain combinations. This completely drops the extra argument that's no longer used. --- diff --git a/include/haproxy/cfgparse.h b/include/haproxy/cfgparse.h index 926b583be..3a1640b11 100644 --- a/include/haproxy/cfgparse.h +++ b/include/haproxy/cfgparse.h @@ -149,7 +149,7 @@ int too_many_args(int maxarg, char **args, char **msg, int *err_code); int alertif_too_many_args_idx(int maxarg, int index, const char *file, int linenum, char **args, int *err_code); int alertif_too_many_args(int maxarg, const char *file, int linenum, char **args, int *err_code); int parse_process_number(const char *arg, unsigned long *proc, int max, int *autoinc, char **err); -const char *cfg_find_best_match(const char *word, const struct list *list, int section, const char **extra); +const char *cfg_find_best_match(const char *word, const struct list *list, int section); int warnifnotcap(struct proxy *proxy, int cap, const char *file, int line, const char *arg, const char *hint); int failifnotcap(struct proxy *proxy, int cap, const char *file, int line, const char *arg, const char *hint); void cfg_dump_registered_keywords(); diff --git a/src/acme.c b/src/acme.c index 63f6959ae..ecf536744 100644 --- a/src/acme.c +++ b/src/acme.c @@ -358,7 +358,7 @@ static int cfg_parse_acme(const char *file, int linenum, char **args, int kwm) } } - best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_ACME, NULL); + best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_ACME); 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 diff --git a/src/cfgparse-global.c b/src/cfgparse-global.c index 90b0c037d..09167daa0 100644 --- a/src/cfgparse-global.c +++ b/src/cfgparse-global.c @@ -102,7 +102,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) if (global.mode & MODE_DISCOVERY) goto out; - best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_GLOBAL, common_kw_list); + best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_GLOBAL); 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 diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 030fdc9e1..23f931d7b 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -568,7 +568,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } } - best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_LISTEN, common_kw_list); + best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_LISTEN); 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 diff --git a/src/cfgparse.c b/src/cfgparse.c index ec181cd56..81e52d871 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -480,15 +480,15 @@ int warnif_tcp_http_cond(const struct proxy *px, const struct acl_cond *cond) /* try to find in the word that looks closest to by counting * transitions between letters, digits and other characters. Will return the - * best matching word if found, otherwise NULL. An optional array of extra - * words to compare may be passed in , but it must then be terminated - * by a NULL entry. If unused it may be NULL. + * best matching word if found, otherwise NULL. If no match is found, then the + * registered section names are checked and a matching one is proposed. */ -const char *cfg_find_best_match(const char *word, const struct list *list, int section, const char **extra) +const char *cfg_find_best_match(const char *word, const struct list *list, int section) { uint8_t word_sig[1024]; // 0..25=letter, 26=digit, 27=other, 28=begin, 29=end uint8_t list_sig[1024]; const struct cfg_kw_list *kwl; + const struct cfg_section *cs; int index; const char *best_ptr = NULL; int dist, best_dist = INT_MAX; @@ -508,14 +508,16 @@ const char *cfg_find_best_match(const char *word, const struct list *list, int s } } - while (extra && *extra) { - make_word_fingerprint(list_sig, *extra); + /* the name of any section is a valid word at this place, and none of + * them is registered as a keyword. + */ + list_for_each_entry(cs, §ions, list) { + make_word_fingerprint(list_sig, cs->section_name); dist = word_fingerprint_distance(word_sig, list_sig); if (dist < best_dist) { best_dist = dist; - best_ptr = *extra; + best_ptr = cs->section_name; } - extra++; } if (best_dist > 2 * strlen(word) || (best_ptr && best_dist > 2 * strlen(best_ptr))) diff --git a/src/ssl_ckch.c b/src/ssl_ckch.c index 3f808ee63..9353e772a 100644 --- a/src/ssl_ckch.c +++ b/src/ssl_ckch.c @@ -5648,7 +5648,7 @@ static int cfg_parse_crtstore(const char *file, int linenum, char **args, int kw } } - best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_CRTSTORE, NULL); + best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_CRTSTORE); 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 diff --git a/src/trace.c b/src/trace.c index c7570f726..f97ed214b 100644 --- a/src/trace.c +++ b/src/trace.c @@ -1264,7 +1264,7 @@ int cfg_parse_traces(const char *file, int linenum, char **args, int inv) } } - best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_TRACES, NULL); + best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_TRACES); 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