From 4de86bbbfc228f0c7e5b8ee31b76ab17a04b2060 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Mon, 10 Feb 2025 15:07:05 +0100 Subject: [PATCH] MEDIUM: initcall: allow to register mutiple post_section_parser per section Before this patch, REGISTER_CONFIG_SECTION() allowed to register one and only one callback () called after the parsing of a section. It was limitating because you couldn't register a post callback from anywhere else in the code. This patch introduces the new REGISTER_CONFIG_SECTION_POST() macros which allows to register a new post callback for a section keyword from anywhere. This patch introduces the feature by allowing `struct cfg_section` entries that does not have a `section_parser`, and then iterating on all cfg_section with a post_section_parser for a keyword. --- doc/internals/api/initcalls.txt | 10 ++++++ include/haproxy/cfgparse.h | 4 +++ src/cfgparse.c | 62 +++++++++++++++++++++++---------- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/doc/internals/api/initcalls.txt b/doc/internals/api/initcalls.txt index a341edc1db..c599640ef5 100644 --- a/doc/internals/api/initcalls.txt +++ b/doc/internals/api/initcalls.txt @@ -314,6 +314,16 @@ alphanumerically ordered: call to cfg_register_section() with the three arguments at stage STG_REGISTER. + You can only register a section once, but you can register post callbacks + multiple time for this section with REGISTER_CONFIG_SECTION_POST(). + +- REGISTER_CONFIG_SECTION_POST(name, post) + + Registers a function which will be called after a section is parsed. This is + the same as the argument in REGISTER_CONFIG_SECTION(), the difference + is that it allows to register multiple callbacks and to register them + elsewhere in the code. + - REGISTER_PER_THREAD_ALLOC(fct) Registers a call to register_per_thread_alloc(fct) at stage STG_REGISTER. diff --git a/include/haproxy/cfgparse.h b/include/haproxy/cfgparse.h index 7b89b7a1f4..89be1fb797 100644 --- a/include/haproxy/cfgparse.h +++ b/include/haproxy/cfgparse.h @@ -151,6 +151,10 @@ ssize_t load_cfg_in_mem(char* filename, char** cfg_content); #define REGISTER_CONFIG_SECTION(name, parse, post) \ INITCALL3(STG_REGISTER, cfg_register_section, (name), (parse), (post)) +/* simplified way to define a post section parser */ +#define REGISTER_CONFIG_POST_SECTION(name, post) \ + INITCALL3(STG_REGISTER, cfg_register_section, (name), NULL, (post)) + #define REGISTER_CONFIG_POSTPARSER(name, parser) \ INITCALL2(STG_REGISTER, cfg_register_postparser, (name), (parser)) diff --git a/src/cfgparse.c b/src/cfgparse.c index bf8bd14e82..acd581058f 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2052,7 +2052,10 @@ next_line: /* if a word is in sections list, is_sect = 1 */ list_for_each_entry(sect, §ions, list) { - if (strcmp(args[0], sect->section_name) == 0) { + /* look for a section_name, but also a section_parser, because there might be + * only a post_section_parser */ + if (strcmp(args[0], sect->section_name) == 0 && + sect->section_parser) { is_sect = 1; break; } @@ -2562,7 +2565,7 @@ next_line: /* detect section start */ list_for_each_entry(ics, §ions, list) { - if (strcmp(args[0], ics->section_name) == 0) { + if (strcmp(args[0], ics->section_name) == 0 && ics->section_parser) { cursection = ics->section_name; pcs = cs; cs = ics; @@ -2573,20 +2576,29 @@ next_line: } } - if (pcs && pcs->post_section_parser) { + if (pcs) { + struct cfg_section *psect; int status; - /* don't call post_section_parser in MODE_DISCOVERY */ - if (global.mode & MODE_DISCOVERY) - goto section_parser; - status = pcs->post_section_parser(); - err_code |= status; - if (status & ERR_FATAL) - fatal++; + /* look for every post_section_parser for the previous section name */ + list_for_each_entry(psect, §ions, list) { + if (strcmp(pcs->section_name, psect->section_name) == 0 && + psect->post_section_parser) { - if (err_code & ERR_ABORT) - goto err; + /* don't call post_section_parser in MODE_DISCOVERY */ + if (global.mode & MODE_DISCOVERY) + goto section_parser; + + status = psect->post_section_parser(); + err_code |= status; + if (status & ERR_FATAL) + fatal++; + + if (err_code & ERR_ABORT) + goto err; + } + } } pcs = NULL; @@ -2625,10 +2637,19 @@ section_parser: ha_free(&global.cfg_curr_section); /* call post_section_parser of the last section when there is no more lines */ - if (cs && cs->post_section_parser) { + if (cs) { + struct cfg_section *psect; + /* don't call post_section_parser in MODE_DISCOVERY */ - if (!(global.mode & MODE_DISCOVERY)) - err_code |= cs->post_section_parser(); + if (!(global.mode & MODE_DISCOVERY)) { + list_for_each_entry(psect, §ions, list) { + if (strcmp(cs->section_name, psect->section_name) == 0 && + psect->post_section_parser) { + + err_code |= cs->post_section_parser(); + } + } + } } if (nested_cond_lvl) { @@ -4722,10 +4743,13 @@ int cfg_register_section(char *section_name, { struct cfg_section *cs; - list_for_each_entry(cs, §ions, list) { - if (strcmp(cs->section_name, section_name) == 0) { - ha_alert("register section '%s': already registered.\n", section_name); - return 0; + if (section_parser) { + /* only checks if we register a section parser, not a post section callback */ + list_for_each_entry(cs, §ions, list) { + if (strcmp(cs->section_name, section_name) == 0 && cs->section_parser) { + ha_alert("register section '%s': already registered.\n", section_name); + return 0; + } } } -- 2.39.5