diff --git a/configfile-scan.l b/configfile-scan.l index a705d2c0..acff07fb 100644 --- a/configfile-scan.l +++ b/configfile-scan.l @@ -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 diff --git a/configfile.c b/configfile.c index 8d162d8e..42bdb029 100644 --- a/configfile.c +++ b/configfile.c @@ -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", diff --git a/configfile.h b/configfile.h index 8da1694b..cc2e64c2 100644 --- a/configfile.h +++ b/configfile.h @@ -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_ */