Initial refactoring of configuration file parsing

Have the configuration file parsing routine itself open the respective
configuration file, rather than passing a file pointer from the original
caller. This is required for handling include directives, which we'll
want to do for sanity-checking the PostgreSQL configuration on a freshly
cloned, unstarted standby.
This commit is contained in:
Ian Barwick
2020-04-29 11:53:26 +09:00
parent 26689871dc
commit f5018e42f3
3 changed files with 97 additions and 15 deletions

View File

@@ -38,7 +38,11 @@ static sigjmp_buf *CONF_flex_fatal_jmp;
static char *CONF_scanstr(const char *s);
static int CONF_flex_fatal(const char *msg);
static bool ProcessConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
static bool ProcessConfigFile(const char *config_file, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
static bool ProcessConfigFp(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
static char *AbsoluteConfigLocation(const char *location, const char *calling_file);
%}
@@ -91,19 +95,59 @@ STRING \'([^'\\\n]|\\.|\'\')*\'
%%
extern bool
ProcessRepmgrConfigFile(FILE *fp, const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
ProcessRepmgrConfigFile(const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
{
return ProcessConfigFile(fp, config_file, NULL, options, error_list, warning_list);
return ProcessConfigFile(config_file, NULL, NULL, options, error_list, warning_list);
}
extern bool
ProcessPostgresConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
ProcessPostgresConfigFile(const char *config_file, KeyValueList *contents, ItemList *error_list, ItemList *warning_list)
{
return ProcessConfigFile(fp, config_file, contents, NULL, error_list, warning_list);
return ProcessConfigFile(config_file, NULL, contents, NULL, error_list, warning_list);
}
static bool
ProcessConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
ProcessConfigFile(const char *config_file, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
{
char *abs_path;
bool success = true;
FILE *fp;
/*
* Reject file name that is all-blank (including empty), as that leads to
* confusion --- we'd try to read the containing directory as a file.
*/
if (strspn(config_file, " \t\r\n") == strlen(config_file))
{
return false;
}
abs_path = AbsoluteConfigLocation(config_file, calling_file);
// XXX reject direct recursion.
fp = fopen(abs_path, "r");
if (!fp)
{
item_list_append_format(error_list,
"could not open configuration file \"%s\": %s",
abs_path,
strerror(errno));
success = false;
}
else
{
success = ProcessConfigFp(fp, abs_path, contents, options, error_list, warning_list);
}
free(abs_path);
return success;
}
static bool
ProcessConfigFp(FILE *fp, const char *config_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list)
{
volatile bool OK = true;
volatile YY_BUFFER_STATE lex_buffer = NULL;
@@ -348,6 +392,36 @@ CONF_scanstr(const char *s)
return newStr;
}
/*
* Given a configuration file or directory location that may be a relative
* path, return an absolute one. We consider the location to be relative to
* the directory holding the calling file, or to DataDir if no calling file.
*/
static char *
AbsoluteConfigLocation(const char *location, const char *calling_file)
{
char abs_path[MAXPGPATH];
if (is_absolute_path(location))
return strdup(location);
else
{
if (calling_file != NULL)
{
strlcpy(abs_path, calling_file, sizeof(abs_path));
get_parent_directory(abs_path);
join_path_components(abs_path, abs_path, location);
canonicalize_path(abs_path);
}
else
{
/*AssertState(DataDir);
join_path_components(abs_path, DataDir, location);
canonicalize_path(abs_path);*/
}
return strdup(abs_path);
}
}
/*
* Flex fatal errors bring us here. Stash the error message and jump back to

View File

@@ -468,13 +468,17 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
return;
}
fp = fopen(config_file_path, "r");
/*
* A configuration file has been found, either provided by the user or
* found in one of the default locations. If we can't open it, fail with
* an error.
* found in one of the default locations. Sanity check whether we
* can open it, and fail with an error about the nature of the file
* (provided or default) if not. We do this here rather than having
* to teach the configuration file parser the difference.
*/
fp = fopen(config_file_path, "r");
if (fp == NULL)
{
if (config_file_provided)
@@ -491,10 +495,12 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *
exit(ERR_BAD_CONFIG);
}
(void) ProcessRepmgrConfigFile(fp, config_file_path, options, error_list, warning_list);
fclose(fp);
// XXX fail here if processing issue found
(void) ProcessRepmgrConfigFile(config_file_path, options, error_list, warning_list);
/* check required parameters */
if (options->node_id == UNKNOWN_NODE_ID)
{
@@ -1951,6 +1957,7 @@ modify_auto_conf(const char *data_dir, KeyValueList *items)
appendPQExpBuffer(&auto_conf, "%s/%s",
data_dir, PG_AUTOCONF_FILENAME);
// XXX do we need this?
fp = fopen(auto_conf.data, "r");
if (fp == NULL)
@@ -1961,10 +1968,11 @@ modify_auto_conf(const char *data_dir, KeyValueList *items)
termPQExpBuffer(&auto_conf);
return false;
}
success = ProcessPostgresConfigFile(fp, auto_conf.data, &config, NULL, NULL);
fclose(fp);
success = ProcessPostgresConfigFile(auto_conf.data, &config, NULL, NULL);
if (success == false)
{
fprintf(stderr, "unable to process \"%s\"\n",

View File

@@ -351,8 +351,8 @@ const char *print_connection_check_type(ConnectionCheckType type);
extern bool modify_auto_conf(const char *data_dir, KeyValueList *items);
extern bool ProcessRepmgrConfigFile(FILE *fp, const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
extern bool ProcessRepmgrConfigFile(const char *config_file, t_configuration_options *options, ItemList *error_list, ItemList *warning_list);
extern bool ProcessPostgresConfigFile(FILE *fp, const char *config_file, KeyValueList *contents, ItemList *error_list, ItemList *warning_list);
extern bool ProcessPostgresConfigFile(const char *config_file, KeyValueList *contents, ItemList *error_list, ItemList *warning_list);
#endif /* _REPMGR_CONFIGFILE_H_ */