From ca1acd60808b6c8b6875cdc8300e546c069b3c77 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 29 Mar 2022 15:02:44 +0200 Subject: [PATCH] MINOR: config: add a function to dump all known config keywords All registered config keywords that are valid in the config parser are dumped to stdout organized like the regular sections (global, listen, etc). Some keywords that are known to only be valid in frontends or backends will be suffixed with [FE] or [BE]. All regularly registered "bind" and "server" keywords are also dumped, one per "bind" or "server" line. Those depending on ssl are listed after the "ssl" keyword. Doing so required to export the listener and server keyword lists that were static. The function is called from dump_registered_keywords() for keyword class "cfg". --- include/haproxy/cfgparse.h | 1 + src/cfgparse.c | 122 +++++++++++++++++++++++++++++++++++++ src/haproxy.c | 6 ++ src/listener.c | 2 +- src/server.c | 2 +- 5 files changed, 131 insertions(+), 2 deletions(-) diff --git a/include/haproxy/cfgparse.h b/include/haproxy/cfgparse.h index 72a3720ff..2708f7685 100644 --- a/include/haproxy/cfgparse.h +++ b/include/haproxy/cfgparse.h @@ -126,6 +126,7 @@ void free_email_alert(struct proxy *p); const char *cfg_find_best_match(const char *word, const struct list *list, int section, const char **extra); 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(); /* simplified way to define a section parser */ #define REGISTER_CONFIG_SECTION(name, parse, post) \ diff --git a/src/cfgparse.c b/src/cfgparse.c index 036a30321..6dd821067 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -4241,6 +4241,128 @@ void cfg_restore_sections(struct list *backup_sections) } } +/* dumps all registered keywords by section on stdout */ +void cfg_dump_registered_keywords() +{ + const char* sect_names[] = { "", "global", "listen", "userlist", "peers", 0 }; + int section; + int index; + + for (section = 1; sect_names[section]; section++) { + struct cfg_kw_list *kwl; + + printf("%s\n", sect_names[section]); + list_for_each_entry(kwl, &cfg_keywords.list, list) { + for (index = 0; kwl->kw[index].kw != NULL; index++) + if (kwl->kw[index].section == section) + printf("\t%s\n", kwl->kw[index].kw); + } + + if (section == CFG_LISTEN) { + /* there are plenty of other keywords there */ + extern struct list tcp_req_conn_keywords, tcp_req_sess_keywords, + tcp_req_cont_keywords, tcp_res_cont_keywords; + extern struct bind_kw_list bind_keywords; + extern struct ssl_bind_kw ssl_bind_kws[] __maybe_unused; + extern struct srv_kw_list srv_keywords; + struct action_kw_list *akwl; + struct bind_kw_list *bkwl; + struct srv_kw_list *skwl; + + list_for_each_entry(bkwl, &bind_keywords.list, list) { + for (index = 0; bkwl->kw[index].kw != NULL; index++) { + if (!bkwl->kw[index].skip) + printf("\tbind %s\n", bkwl->kw[index].kw); + else + printf("\tbind %s +%d\n", bkwl->kw[index].kw, bkwl->kw[index].skip); + } + } + +#if defined(USE_OPENSSL) + for (index = 0; ssl_bind_kws[index].kw != NULL; index++) { + if (!ssl_bind_kws[index].skip) + printf("\tbind ssl %s\n", ssl_bind_kws[index].kw); + else + printf("\tbind ssl %s +%d\n", ssl_bind_kws[index].kw, ssl_bind_kws[index].skip); + } +#endif + + list_for_each_entry(skwl, &srv_keywords.list, list) { + for (index = 0; skwl->kw[index].kw != NULL; index++) { + if (!skwl->kw[index].skip) + printf("\tserver %s\n", skwl->kw[index].kw); + else + printf("\tserver %s +%d\n", skwl->kw[index].kw, skwl->kw[index].skip); + } + } + + for (index = 0; cfg_opts[index].name; index++) { + printf("\toption %s [ ", cfg_opts[index].name); + if (cfg_opts[index].cap & PR_CAP_FE) + printf("FE "); + if (cfg_opts[index].cap & PR_CAP_BE) + printf("BE "); + if (cfg_opts[index].mode == PR_MODE_HTTP) + printf("HTTP "); + printf("]\n"); + } + + for (index = 0; cfg_opts2[index].name; index++) { + printf("\toption %s [ ", cfg_opts2[index].name); + if (cfg_opts2[index].cap & PR_CAP_FE) + printf("FE "); + if (cfg_opts2[index].cap & PR_CAP_BE) + printf("BE "); + if (cfg_opts2[index].mode == PR_MODE_HTTP) + printf("HTTP "); + printf("]\n"); + } + + list_for_each_entry(akwl, &tcp_req_conn_keywords, list) { + for (index = 0; akwl->kw[index].kw != NULL; index++) + printf("\ttcp-request connection %s%s\n", akwl->kw[index].kw, + (akwl->kw[index].flags & KWF_MATCH_PREFIX) ? "*" : ""); + } + + list_for_each_entry(akwl, &tcp_req_sess_keywords, list) { + for (index = 0; akwl->kw[index].kw != NULL; index++) + printf("\ttcp-request session %s%s\n", akwl->kw[index].kw, + (akwl->kw[index].flags & KWF_MATCH_PREFIX) ? "*" : ""); + } + + list_for_each_entry(akwl, &tcp_req_cont_keywords, list) { + for (index = 0; akwl->kw[index].kw != NULL; index++) + printf("\ttcp-request content %s%s\n", akwl->kw[index].kw, + (akwl->kw[index].flags & KWF_MATCH_PREFIX) ? "*" : ""); + } + + list_for_each_entry(akwl, &tcp_res_cont_keywords, list) { + for (index = 0; akwl->kw[index].kw != NULL; index++) + printf("\ttcp-response content %s%s\n", akwl->kw[index].kw, + (akwl->kw[index].flags & KWF_MATCH_PREFIX) ? "*" : ""); + } + + list_for_each_entry(akwl, &http_req_keywords.list, list) { + for (index = 0; akwl->kw[index].kw != NULL; index++) + printf("\thttp-request %s%s\n", akwl->kw[index].kw, + (akwl->kw[index].flags & KWF_MATCH_PREFIX) ? "*" : ""); + } + + list_for_each_entry(akwl, &http_res_keywords.list, list) { + for (index = 0; akwl->kw[index].kw != NULL; index++) + printf("\thttp-response %s%s\n", akwl->kw[index].kw, + (akwl->kw[index].flags & KWF_MATCH_PREFIX) ? "*" : ""); + } + + list_for_each_entry(akwl, &http_after_res_keywords.list, list) { + for (index = 0; akwl->kw[index].kw != NULL; index++) + printf("\thttp-after-response %s%s\n", akwl->kw[index].kw, + (akwl->kw[index].flags & KWF_MATCH_PREFIX) ? "*" : ""); + } + } + } +} + /* these are the config sections handled by default */ REGISTER_CONFIG_SECTION("listen", cfg_parse_listen, NULL); REGISTER_CONFIG_SECTION("frontend", cfg_parse_listen, NULL); diff --git a/src/haproxy.c b/src/haproxy.c index a037611e6..b5f368d1e 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1825,11 +1825,17 @@ static void dump_registered_keywords(void) if (strcmp(kwd_dump, "help") == 0) { printf("# List of supported keyword classes:\n"); printf("all: list all keywords\n"); + printf("cfg: configuration keywords\n"); continue; } else if (strcmp(kwd_dump, "all") == 0) { all = 1; } + + if (all || strcmp(kwd_dump, "cfg") == 0) { + printf("# List of registered configuration keywords:\n"); + cfg_dump_registered_keywords(); + } } } diff --git a/src/listener.c b/src/listener.c index 82463b81a..1e1a83284 100644 --- a/src/listener.c +++ b/src/listener.c @@ -40,7 +40,7 @@ /* List head of all known bind keywords */ -static struct bind_kw_list bind_keywords = { +struct bind_kw_list bind_keywords = { .list = LIST_HEAD_INIT(bind_keywords.list) }; diff --git a/src/server.c b/src/server.c index d3f86b058..a87f864b5 100644 --- a/src/server.c +++ b/src/server.c @@ -62,7 +62,7 @@ static const char *extra_kw_list[] = { }; /* List head of all known server keywords */ -static struct srv_kw_list srv_keywords = { +struct srv_kw_list srv_keywords = { .list = LIST_HEAD_INIT(srv_keywords.list) };