MEDIUM: startup: load and parse configs from memory

Let's call load_cfg_in_ram() helper for each configuration file to load it's
content in some area in memory. Adapt readcfgfile() parser function
respectively. In order to limit changes in its scope we give as an argument a
cfgfile structure, already filled in init_args() and in load_cfg_in_ram() with
file metadata and content.

Parser function (readcfgfile()) uses now fgets_from_mem() instead of standard
fgets from libc implementations.

SPOE filter parses its own configuration file, pointed by 'config' keyword in
the configuration already loaded in memory. So, let's allocate and fill for
this a supplementary cfgfile structure, which is not referenced in cfg_cfgfiles
list. This structure and the memory with content of SPOE filter configuration
are freed immediately in parse_spoe_flt(), when readcfgfile() returns.

HAProxy OpenTracing filter also uses its own configuration file. So, let's
follow the same logic as we do for SPOE filter.
This commit is contained in:
Valentine Krasnobaeva 2024-08-07 16:53:50 +02:00 committed by Willy Tarreau
parent 2bb34edb0b
commit 5b52df4c4d
5 changed files with 43 additions and 22 deletions

View File

@ -1074,8 +1074,9 @@ static int flt_ot_post_parse_cfg_scope(void)
*/ */
static int flt_ot_parse_cfg(struct flt_ot_conf *conf, const char *flt_name, char **err) static int flt_ot_parse_cfg(struct flt_ot_conf *conf, const char *flt_name, char **err)
{ {
struct list backup_sections; struct list backup_sections;
int retval = ERR_ABORT | ERR_ALERT; struct cfgfile cfg_file = {0};
int retval = ERR_ABORT | ERR_ALERT;
FLT_OT_FUNC("%p, \"%s\", %p:%p", conf, flt_name, FLT_OT_DPTR_ARGS(err)); FLT_OT_FUNC("%p, \"%s\", %p:%p", conf, flt_name, FLT_OT_DPTR_ARGS(err));
@ -1094,8 +1095,16 @@ static int flt_ot_parse_cfg(struct flt_ot_conf *conf, const char *flt_name, char
/* Do nothing. */; /* Do nothing. */;
else if (access(conf->cfg_file, R_OK) == -1) else if (access(conf->cfg_file, R_OK) == -1)
FLT_OT_PARSE_ERR(err, "'%s' : %s", conf->cfg_file, strerror(errno)); FLT_OT_PARSE_ERR(err, "'%s' : %s", conf->cfg_file, strerror(errno));
else else {
retval = readcfgfile(conf->cfg_file); cfg_file.filename = conf->cfg_file;
cfg_file.size = load_cfg_in_mem(cfg_file.filename, &cfg_file.content);
if (cfg_file.size < 0) {
ha_free(&cfg_file.content);
FLT_OT_RETURN_INT(retval);
}
retval = readcfgfile(&cfg_file);
ha_free(&cfg_file.content);
}
/* Unregister OT sections and restore previous sections. */ /* Unregister OT sections and restore previous sections. */
cfg_unregister_sections(); cfg_unregister_sections();

View File

@ -112,7 +112,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int inv);
int cfg_parse_listen(const char *file, int linenum, char **args, int inv); int cfg_parse_listen(const char *file, int linenum, char **args, int inv);
int cfg_parse_track_sc_num(unsigned int *track_sc_num, int cfg_parse_track_sc_num(unsigned int *track_sc_num,
const char *arg, const char *end, char **err); const char *arg, const char *end, char **err);
int readcfgfile(const char *file); int readcfgfile(const struct cfgfile *cfg);
void cfg_register_keywords(struct cfg_kw_list *kwl); void cfg_register_keywords(struct cfg_kw_list *kwl);
void cfg_unregister_keywords(struct cfg_kw_list *kwl); void cfg_unregister_keywords(struct cfg_kw_list *kwl);
int check_config_validity(void); int check_config_validity(void);

View File

@ -1816,8 +1816,8 @@ free_mem:
} }
/* /*
* This function reads and parses the configuration file given in the argument. * This function parses the configuration file given in the argument.
* Returns the error code, 0 if OK, -1 if the config file couldn't be opened, * Returns the error code, 0 if OK, -1 if we are run out of memory,
* or any combination of : * or any combination of :
* - ERR_ABORT: must abort ASAP * - ERR_ABORT: must abort ASAP
* - ERR_FATAL: we can continue parsing but not start the service * - ERR_FATAL: we can continue parsing but not start the service
@ -1826,11 +1826,10 @@ free_mem:
* Only the two first ones can stop processing, the two others are just * Only the two first ones can stop processing, the two others are just
* indicators. * indicators.
*/ */
int readcfgfile(const char *file) int readcfgfile(const struct cfgfile *cfg)
{ {
char *thisline = NULL; char *thisline = NULL;
int linesize = LINESIZE; int linesize = LINESIZE;
FILE *f = NULL;
int linenum = 0; int linenum = 0;
int err_code = 0; int err_code = 0;
struct cfg_section *cs = NULL, *pcs = NULL; struct cfg_section *cs = NULL, *pcs = NULL;
@ -1844,6 +1843,8 @@ int readcfgfile(const char *file)
int nested_cond_lvl = 0; int nested_cond_lvl = 0;
enum nested_cond_state nested_conds[MAXNESTEDCONDS]; enum nested_cond_state nested_conds[MAXNESTEDCONDS];
char *errmsg = NULL; char *errmsg = NULL;
const char *cur_position = cfg->content;
char *file = cfg->filename;
global.cfg_curr_line = 0; global.cfg_curr_line = 0;
global.cfg_curr_file = file; global.cfg_curr_file = file;
@ -1854,11 +1855,6 @@ int readcfgfile(const char *file)
goto err; goto err;
} }
if ((f = fopen(file,"r")) == NULL) {
err_code = -1;
goto err;
}
/* change to the new dir if required */ /* change to the new dir if required */
if (!cfg_apply_default_path(file, NULL, &errmsg)) { if (!cfg_apply_default_path(file, NULL, &errmsg)) {
ha_alert("parsing [%s:%d]: failed to apply default-path: %s.\n", file, linenum, errmsg); ha_alert("parsing [%s:%d]: failed to apply default-path: %s.\n", file, linenum, errmsg);
@ -1868,7 +1864,8 @@ int readcfgfile(const char *file)
} }
next_line: next_line:
while (fgets(thisline + readbytes, linesize - readbytes, f) != NULL) { while (fgets_from_mem(thisline + readbytes, linesize - readbytes,
&cur_position, cfg->content + cfg->size)) {
int arg, kwm = KWM_STD; int arg, kwm = KWM_STD;
char *end; char *end;
char *args[MAX_LINE_ARGS + 1]; char *args[MAX_LINE_ARGS + 1];
@ -2617,9 +2614,6 @@ err:
global.cfg_curr_line = 0; global.cfg_curr_line = 0;
global.cfg_curr_file = NULL; global.cfg_curr_file = NULL;
if (f)
fclose(f);
return err_code; return err_code;
} }

View File

@ -2199,6 +2199,7 @@ static int parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
struct spoe_group *grp, *grpback; struct spoe_group *grp, *grpback;
struct spoe_placeholder *ph, *phback; struct spoe_placeholder *ph, *phback;
struct spoe_var_placeholder *vph, *vphback; struct spoe_var_placeholder *vph, *vphback;
struct cfgfile cfg_file = {0};
struct logger *logger, *loggerback; struct logger *logger, *loggerback;
char *file = NULL, *engine = NULL; char *file = NULL, *engine = NULL;
int ret, pos = *cur_arg + 1; int ret, pos = *cur_arg + 1;
@ -2260,7 +2261,19 @@ static int parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
curengine = engine; curengine = engine;
curagent = NULL; curagent = NULL;
curmsg = NULL; curmsg = NULL;
ret = readcfgfile(file);
/* load the content of SPOE config file from cfg_file.filename into some
* area in .heap. readcfgfile() now parses the content of config files
* stored in RAM as separate chunks (see struct cfgfile in cfgparse.h),
* these chunks chained in cfg_cfgfiles global list.
*/
cfg_file.filename = file;
cfg_file.size = load_cfg_in_mem(file, &cfg_file.content);
if (cfg_file.size < 0) {
goto error;
}
ret = readcfgfile(&cfg_file);
ha_free(&cfg_file.content);
/* unregister SPOE sections and restore previous sections */ /* unregister SPOE sections and restore previous sections */
cfg_unregister_sections(); cfg_unregister_sections();
@ -2579,6 +2592,7 @@ static int parse_spoe_flt(char **args, int *cur_arg, struct proxy *px,
return 0; return 0;
error: error:
ha_free(&cfg_file.content);
spoe_release_agent(curagent); spoe_release_agent(curagent);
list_for_each_entry_safe(ph, phback, &curmphs, list) { list_for_each_entry_safe(ph, phback, &curmphs, list) {
LIST_DELETE(&ph->list); LIST_DELETE(&ph->list);

View File

@ -1174,7 +1174,7 @@ next_dir_entry:
static int read_cfg(char *progname) static int read_cfg(char *progname)
{ {
char *env_cfgfiles = NULL; char *env_cfgfiles = NULL;
struct cfgfile *cfg; struct cfgfile *cfg, *cfg_tmp;
int err_code = 0; int err_code = 0;
/* handle cfgfiles that are actually directories */ /* handle cfgfiles that are actually directories */
@ -1191,9 +1191,13 @@ static int read_cfg(char *progname)
setenv("HAPROXY_HTTPS_LOG_FMT", default_https_log_format, 1); setenv("HAPROXY_HTTPS_LOG_FMT", default_https_log_format, 1);
setenv("HAPROXY_TCP_LOG_FMT", default_tcp_log_format, 1); setenv("HAPROXY_TCP_LOG_FMT", default_tcp_log_format, 1);
setenv("HAPROXY_BRANCH", PRODUCT_BRANCH, 1); setenv("HAPROXY_BRANCH", PRODUCT_BRANCH, 1);
list_for_each_entry(cfg, &cfg_cfgfiles, list) { list_for_each_entry_safe(cfg, cfg_tmp, &cfg_cfgfiles, list) {
int ret; int ret;
cfg->size = load_cfg_in_mem(cfg->filename, &cfg->content);
if (cfg->size < 0)
goto err;
if (!memprintf(&env_cfgfiles, "%s%s%s", if (!memprintf(&env_cfgfiles, "%s%s%s",
(env_cfgfiles ? env_cfgfiles : ""), (env_cfgfiles ? env_cfgfiles : ""),
(env_cfgfiles ? ";" : ""), cfg->filename)) { (env_cfgfiles ? ";" : ""), cfg->filename)) {
@ -1202,7 +1206,7 @@ static int read_cfg(char *progname)
goto err; goto err;
} }
ret = readcfgfile(cfg->filename); ret = readcfgfile(cfg);
if (ret == -1) if (ret == -1)
goto err; goto err;