diff --git a/configfile-scan.l b/configfile-scan.l index 011fb68f..72cc1198 100644 --- a/configfile-scan.l +++ b/configfile-scan.l @@ -40,11 +40,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(const char *base_dir, const char *config_file, const char *calling_file, bool strict, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list); +static bool ProcessConfigFile(const char *base_dir, const char *config_file, const char *calling_file, bool strict, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list); -static bool ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, const char *base_dir, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list); +static bool ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, const char *base_dir, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list); -static bool ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list); +static bool ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list); static char *AbsoluteConfigLocation(const char *base_dir, const char *location, const char *calling_file); @@ -101,19 +101,26 @@ STRING \'([^'\\\n]|\\.|\'\')*\' extern bool ProcessRepmgrConfigFile(const char *config_file, const char *base_dir, t_configuration_options *options, ItemList *error_list, ItemList *warning_list) { - return ProcessConfigFile(base_dir, config_file, NULL, true, NULL, options, error_list, warning_list); + return ProcessConfigFile(base_dir, config_file, NULL, true, NULL, options, NULL, error_list, warning_list); } +extern bool +ProcessRepmgrConfigFile2(const char *config_file, const char *base_dir, ItemList *error_list, ItemList *warning_list) +{ + return ProcessConfigFile(base_dir, config_file, NULL, true, NULL, NULL, NULL, error_list, warning_list); +} + + extern bool ProcessPostgresConfigFile(const char *config_file, const char *base_dir, KeyValueList *contents, ItemList *error_list, ItemList *warning_list) { printf("ProcessPostgresConfigFile(): base: %s file: %s\n", base_dir, config_file); - return ProcessConfigFile(base_dir, config_file, NULL, true, contents, NULL, error_list, warning_list); + return ProcessConfigFile(base_dir, config_file, NULL, true, contents, NULL, NULL, error_list, warning_list); } static bool -ProcessConfigFile(const char *base_dir, const char *config_file, const char *calling_file, bool strict, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list) +ProcessConfigFile(const char *base_dir, const char *config_file, const char *calling_file, bool strict, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list) { char *abs_path; bool success = true; @@ -152,7 +159,7 @@ ProcessConfigFile(const char *base_dir, const char *config_file, const char *cal } else { - success = ProcessConfigFp(fp, abs_path, calling_file, base_dir, contents, options, error_list, warning_list); + success = ProcessConfigFp(fp, abs_path, calling_file, base_dir, contents, options, options2, error_list, warning_list); } free(abs_path); @@ -161,7 +168,7 @@ ProcessConfigFile(const char *base_dir, const char *config_file, const char *cal } static bool -ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, const char *base_dir, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list) +ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, const char *base_dir, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list) { volatile bool OK = true; volatile YY_BUFFER_STATE lex_buffer = NULL; @@ -245,7 +252,7 @@ ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, con * processed immediately. */ if (!ProcessConfigDirectory(base_dir, opt_value, config_file, - contents, options, + contents, options, options2, error_list, warning_list)) OK = false; yy_switch_to_buffer(lex_buffer); @@ -255,7 +262,7 @@ ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, con else if (base_dir != NULL && strcasecmp(opt_name, "include_if_exists") == 0) { if (!ProcessConfigFile(base_dir, opt_value, config_file, - false, contents, options, + false, contents, options, options2, error_list, warning_list)) OK = false; @@ -266,7 +273,7 @@ ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, con else if (base_dir != NULL && strcasecmp(opt_name, "include") == 0) { if (!ProcessConfigFile(base_dir, opt_value, config_file, - true, contents, options, + true, contents, options, options2, error_list, warning_list)) OK = false; @@ -292,6 +299,15 @@ ProcessConfigFp(FILE *fp, const char *config_file, const char *calling_file, con opt_name, opt_value); } + + if (1) + { + parse_configuration_item2(error_list, + warning_list, + opt_name, + opt_value); + } + } @@ -360,7 +376,7 @@ cleanup: * See ProcessConfigFp for further details. */ static bool -ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ItemList *error_list, ItemList *warning_list) +ProcessConfigDirectory(const char *base_dir, const char *includedir, const char *calling_file, KeyValueList *contents, t_configuration_options *options, ConfigFileOption *options2, ItemList *error_list, ItemList *warning_list) { char *directory; DIR *d; @@ -461,7 +477,7 @@ ProcessConfigDirectory(const char *base_dir, const char *includedir, const char for (i = 0; i < num_filenames; i++) { if (!ProcessConfigFile(base_dir, filenames[i], calling_file, - true, contents, options, + true, contents, options, options2, error_list, warning_list)) { status = false; diff --git a/configfile.c b/configfile.c index dc9ed907..d06d7391 100644 --- a/configfile.c +++ b/configfile.c @@ -35,12 +35,98 @@ static bool config_file_provided = false; bool config_file_found = false; t_configuration_options config_file_options; + +t_configuration_options config_file_options = T_CONFIGURATION_OPTIONS_INITIALIZER; + +struct ConfigFileOption config_file_options2[] = +{ + + /* ================ + * node information + * ================ + */ + /* node_id */ + { + "node_id", + CONFIG_INT, + { .intptr = &config_file_options.node_id }, + { .intdefault = UNKNOWN_NODE_ID }, + MIN_NODE_ID, + -1 + }, + /* node_name */ + { + "node_name", + CONFIG_STRING, + { .strptr = config_file_options.node_name }, + { .strdefault = NULL }, + -1, + sizeof(config_file_options.node_name) + }, + + /* ====================== + * standby clone settings + * ====================== + */ + /* use_replication_slots */ + { + "use_replication_slots", + CONFIG_BOOL, + { .boolptr = &config_file_options.use_replication_slots }, + { .booldefault = false }, + -1, + -1 + }, + /* ================ + * repmgrd settings + * ================ + */ + /* failover */ + { + "failover", + CONFIG_FAILOVER_MODE, + { .failovermodeptr = &config_file_options.failover }, + { .failovermodedefault = FAILOVER_MANUAL }, + -1, + -1 + }, + /* connection_check_type */ + { + "connection_check_type", + CONFIG_CONNECTION_CHECK_TYPE, + { .checktypeptr = &config_file_options.connection_check_type }, + { .checktypedefault = CHECK_PING }, + -1, + -1 + }, + /* =========================== + * event notification settings + * =========================== + */ + { + "event_notifications", + CONFIG_EVENT_NOTIFICATION_LIST, + { .notificationlistptr = &config_file_options.event_notifications }, + { .notificationlistdefault = NULL }, + -1, + -1 + }, + /* End-of-list marker */ + { + NULL, CONFIG_INT, {}, {}, -1, -1 + } +}; + + static void parse_config(bool terse); +static void parse_config2(bool terse); + static void _parse_config(t_configuration_options *options, ItemList *error_list, ItemList *warning_list); +static void _parse_config2(ItemList *error_list, ItemList *warning_list); static void _parse_line(char *buf, char *name, char *value); -static void parse_event_notifications_list(t_configuration_options *options, const char *arg); -static void clear_event_notification_list(t_configuration_options *options); +static void parse_event_notifications_list(EventNotificationList *event_notifications, const char *arg); +static void clear_event_notification_list(EventNotificationList *event_notifications); static void parse_time_unit_parameter(const char *name, const char *value, char *dest, ItemList *errors); @@ -245,6 +331,186 @@ end_search: return; } +void +load_config2(const char *config_file, bool verbose, bool terse, char *argv0) +{ + struct stat stat_config; + + /* + * If a configuration file was provided, check it exists, otherwise emit + * an error and terminate. We assume that if a user explicitly provides a + * configuration file, they'll want to make sure it's used and not fall + * back to any of the defaults. + */ + if (config_file != NULL && config_file[0] != '\0') + { + strncpy(config_file_path, config_file, MAXPGPATH); + canonicalize_path(config_file_path); + + /* relative path supplied - convert to absolute path */ + if (config_file_path[0] != '/') + { + PQExpBufferData fullpath; + char *pwd = NULL; + + initPQExpBuffer(&fullpath); + + /* + * we'll attempt to use $PWD to derive the effective path; getcwd() + * will likely resolve symlinks, which may result in a path which + * isn't permanent (e.g. if filesystem mountpoints change). + */ + pwd = getenv("PWD"); + + if (pwd != NULL) + { + appendPQExpBufferStr(&fullpath, pwd); + } + else + { + /* $PWD not available - fall back to getcwd() */ + char cwd[MAXPGPATH] = ""; + + if (getcwd(cwd, MAXPGPATH) == NULL) + { + log_error(_("unable to execute getcwd()")); + log_detail("%s", strerror(errno)); + + termPQExpBuffer(&fullpath); + exit(ERR_BAD_CONFIG); + } + + appendPQExpBufferStr(&fullpath, cwd); + } + + appendPQExpBuffer(&fullpath, + "/%s", config_file_path); + + log_debug("relative configuration file converted to:\n \"%s\"", + fullpath.data); + + strncpy(config_file_path, fullpath.data, MAXPGPATH); + + termPQExpBuffer(&fullpath); + + canonicalize_path(config_file_path); + } + + + if (stat(config_file_path, &stat_config) != 0) + { + log_error(_("provided configuration file \"%s\" not found"), + config_file); + log_detail("%s", strerror(errno)); + exit(ERR_BAD_CONFIG); + } + + + if (verbose == true) + { + log_notice(_("using provided configuration file \"%s\""), config_file); + } + + config_file_provided = true; + config_file_found = true; + } + + + /*----------- + * If no configuration file was provided, attempt to find a default file + * in this order: + * - location provided by packager + * - current directory + * - /etc/repmgr.conf + * - default sysconfdir + * + * here we just check for the existence of the file; parse_config() will + * handle read errors etc. + * + *----------- + */ + if (config_file_provided == false) + { + /* packagers: if feasible, patch configuration file path into "package_conf_file" */ + char package_conf_file[MAXPGPATH] = ""; + char my_exec_path[MAXPGPATH] = ""; + char sysconf_etc_path[MAXPGPATH] = ""; + + /* 1. location provided by packager */ + if (package_conf_file[0] != '\0') + { + if (verbose == true) + fprintf(stdout, _("INFO: checking for package configuration file \"%s\"\n"), package_conf_file); + + if (stat(package_conf_file, &stat_config) == 0) + { + strncpy(config_file_path, package_conf_file, MAXPGPATH); + config_file_found = true; + goto end_search; + } + } + + /* 2 "./repmgr.conf" */ + log_verbose(LOG_INFO, _("looking for configuration file in current directory\n")); + + maxpath_snprintf(config_file_path, "./%s", CONFIG_FILE_NAME); + canonicalize_path(config_file_path); + + if (stat(config_file_path, &stat_config) == 0) + { + config_file_found = true; + goto end_search; + } + + /* 3. "/etc/repmgr.conf" */ + if (verbose == true) + fprintf(stdout, _("INFO: looking for configuration file in /etc\n")); + + maxpath_snprintf(config_file_path, "/etc/%s", CONFIG_FILE_NAME); + if (stat(config_file_path, &stat_config) == 0) + { + config_file_found = true; + goto end_search; + } + + /* 4. default sysconfdir */ + if (find_my_exec(argv0, my_exec_path) < 0) + { + fprintf(stderr, _("ERROR: %s: could not find own program executable\n"), argv0); + exit(EXIT_FAILURE); + } + + get_etc_path(my_exec_path, sysconf_etc_path); + + if (verbose == true) + fprintf(stdout, _("INFO: looking for configuration file in \"%s\"\n"), sysconf_etc_path); + + maxpath_snprintf(config_file_path, "%s/%s", sysconf_etc_path, CONFIG_FILE_NAME); + if (stat(config_file_path, &stat_config) == 0) + { + config_file_found = true; + goto end_search; + } + +end_search: + if (verbose == true) + { + if (config_file_found == true) + { + fprintf(stdout, _("INFO: configuration file found at: \"%s\"\n"), config_file_path); + } + else + { + fprintf(stdout, _("INFO: no configuration file provided or found\n")); + } + } + } + + parse_config2(terse); + + return; +} + static void parse_config(bool terse) @@ -271,6 +537,255 @@ parse_config(bool terse) return; } + + +static void +parse_config2(bool terse) +{ + /* Collate configuration file errors here for friendlier reporting */ + static ItemList config_errors = {NULL, NULL}; + static ItemList config_warnings = {NULL, NULL}; + + _parse_config2(&config_errors, &config_warnings); + + /* errors found - exit after printing details, and any warnings */ + if (config_errors.head != NULL) + { + exit_with_config_file_errors(&config_errors, &config_warnings, terse); + } + + if (terse == false && config_warnings.head != NULL) + { + log_warning(_("the following problems were found in the configuration file:")); + + print_item_list(&config_warnings); + } + + return; +} + + +static void +_parse_config2(ItemList *error_list, ItemList *warning_list) +{ + FILE *fp; + char base_directory[MAXPGPATH]; + + + /* + * If no configuration file available (user didn't specify and none found + * in the default locations), return with default values + */ + if (config_file_found == false) + { + log_verbose(LOG_NOTICE, + _("no configuration file provided and no default file found - " + "continuing with default values")); + return; + } + + /* + * A configuration file has been found, either provided by the user or + * 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) + { + log_error(_("unable to open provided configuration file \"%s\"; terminating"), + config_file_path); + } + else + { + log_error(_("unable to open default configuration file \"%s\"; terminating"), + config_file_path); + } + + exit(ERR_BAD_CONFIG); + } + + fclose(fp); + + strncpy(base_directory, config_file_path, MAXPGPATH); + canonicalize_path(base_directory); + get_parent_directory(base_directory); + + // XXX fail here if processing issue found + (void) ProcessRepmgrConfigFile2(config_file_path, base_directory, error_list, warning_list); + + /* check required parameters */ + // ... + + { + ConfigFileOption *option = &config_file_options2[0]; + int i = 0; + + do { + switch (option->type) + { + case CONFIG_INT: + printf(" %s: %i\n", option->name, *option->val.intptr); + break; + case CONFIG_STRING: + printf(" %s: %s\n", option->name, option->val.strptr); + break; + case CONFIG_BOOL: + printf(" %s: %s\n", option->name, format_bool(*option->val.boolptr)); + break; + case CONFIG_FAILOVER_MODE: + printf(" %s: %s\n", option->name, format_failover_mode(*option->val.failovermodeptr)); + break; + case CONFIG_CONNECTION_CHECK_TYPE: + printf(" %s: %s\n", option->name, print_connection_check_type(*option->val.checktypeptr)); + break; + case CONFIG_EVENT_NOTIFICATION_LIST: + { + char *list_str = print_event_notification_list(option->val.notificationlistptr); + printf(" %s: %s\n", option->name, list_str); + pfree(list_str); + break; + } + } + i++; + option = &config_file_options2[i]; + } while (option->name != NULL); + } +} + + +void +parse_configuration_item2(ItemList *error_list, ItemList *warning_list, const char *name, const char *value) +{ + ConfigFileOption *option = &config_file_options2[0]; + int i = 0; + + do { + if (strcmp(name, option->name) == 0) + { + //printf("%s = '%s'\n", name, value); + + switch (option->type) + { + case CONFIG_INT: + *(int *)option->val.intptr = repmgr_atoi(value, name, error_list, option->minval); + break; + case CONFIG_STRING: + strncpy((char *)option->val.strptr, value, option->strmaxlen); + break; + case CONFIG_BOOL: + *(bool *)option->val.boolptr = parse_bool(value, name, error_list); + break; + case CONFIG_FAILOVER_MODE: + { + if (strcmp(value, "manual") == 0) + { + *(failover_mode_opt *)option->val.failovermodeptr = FAILOVER_MANUAL; + } + else if (strcmp(value, "automatic") == 0) + { + *(failover_mode_opt *)option->val.failovermodeptr = FAILOVER_AUTOMATIC; + } + else + { + item_list_append_format(error_list, + _("value for \"%s\" must be \"automatic\" or \"manual\"\n"), + name); + } + break; + } + case CONFIG_CONNECTION_CHECK_TYPE: + { + if (strcasecmp(value, "ping") == 0) + { + *(ConnectionCheckType *)option->val.checktypeptr = CHECK_PING; + } + else if (strcasecmp(value, "connection") == 0) + { + *(ConnectionCheckType *)option->val.checktypeptr = CHECK_CONNECTION; + } + else if (strcasecmp(value, "query") == 0) + { + *(ConnectionCheckType *)option->val.checktypeptr = CHECK_QUERY; + } + else + { + item_list_append_format(error_list, + _("value for \"%s\" must be \"ping\", \"connection\" or \"query\"\n"), + name); + } + break; + } + case CONFIG_EVENT_NOTIFICATION_LIST: + { + parse_event_notifications_list((EventNotificationList *)&option->val.notificationlistptr, value); + } + default: + log_error("encountered unknown configuration type %i when processing \"%s\"", + (int)option->type, + option->name); + } + + } + i++; + option = &config_file_options2[i]; + } while (option->name); + + + /* If we reach here, the configuration item is either deprecated or unknown */ + if (strcmp(name, "cluster") == 0) + { + item_list_append(warning_list, + _("parameter \"cluster\" is deprecated and will be ignored")); + } + else if (strcmp(name, "node") == 0) + { + item_list_append(warning_list, + _("parameter \"node\" has been renamed to \"node_id\"")); + } + else if (strcmp(name, "upstream_node") == 0) + { + item_list_append(warning_list, + _("parameter \"upstream_node\" has been removed; use \"--upstream-node-id\" when cloning a standby")); + } + else if (strcmp(name, "loglevel") == 0) + { + item_list_append(warning_list, + _("parameter \"loglevel\" has been renamed to \"log_level\"")); + } + else if (strcmp(name, "logfacility") == 0) + { + item_list_append(warning_list, + _("parameter \"logfacility\" has been renamed to \"log_facility\"")); + } + else if (strcmp(name, "logfile") == 0) + { + item_list_append(warning_list, + _("parameter \"logfile\" has been renamed to \"log_file\"")); + } + else if (strcmp(name, "master_reponse_timeout") == 0) + { + item_list_append(warning_list, + _("parameter \"master_reponse_timeout\" has been removed; use \"async_query_timeout\" instead")); + } + else if (strcmp(name, "retry_promote_interval_secs") == 0) + { + item_list_append(warning_list, + _("parameter \"retry_promote_interval_secs\" has been removed; use \"primary_notification_timeout\" instead")); + } + else + { + // why not just append to the warning list? + //log_warning(_("%s/%s: unknown name/value pair provided; ignoring"), name, value); + } + +} + /* * This creates a parsed representation of the configuration file in a location provided * by the caller. @@ -285,7 +800,7 @@ _parse_config(t_configuration_options *options, ItemList *error_list, ItemList * * Clear lists pointing to allocated memory */ - clear_event_notification_list(options); + clear_event_notification_list(&options->event_notifications); tablespace_list_free(options); /* Initialize configuration options with sensible defaults */ @@ -830,7 +1345,7 @@ parse_configuration_item(t_configuration_options *options, ItemList *error_list, { /* store unparsed value for comparison when reloading config */ strncpy(options->event_notifications_orig, value, sizeof(options->event_notifications_orig)); - parse_event_notifications_list(options, value); + parse_event_notifications_list(&options->event_notifications, value); } /* barman settings */ @@ -1820,7 +2335,7 @@ copy_config_file_options(t_configuration_options *original, t_configuration_opti if (original->event_notifications.head != NULL) { /* For the event notifications, we can just reparse the string */ - parse_event_notifications_list(copy, original->event_notifications_orig); + parse_event_notifications_list(©->event_notifications, original->event_notifications_orig); } if (original->tablespace_mapping.head != NULL) @@ -2081,7 +2596,7 @@ modify_auto_conf(const char *data_dir, KeyValueList *items) */ static void -parse_event_notifications_list(t_configuration_options *options, const char *arg) +parse_event_notifications_list(EventNotificationList *event_notifications, const char *arg) { const char *arg_ptr = NULL; char event_type_buf[MAXLEN] = ""; @@ -2113,16 +2628,16 @@ parse_event_notifications_list(t_configuration_options *options, const char *arg strncpy(cell->event_type, event_type_buf, MAXLEN); - if (options->event_notifications.tail) + if (event_notifications->tail) { - options->event_notifications.tail->next = cell; + event_notifications->tail->next = cell; } else { - options->event_notifications.head = cell; + event_notifications->head = cell; } - options->event_notifications.tail = cell; + event_notifications->tail = cell; memset(event_type_buf, 0, MAXLEN); dst_ptr = event_type_buf; @@ -2141,14 +2656,14 @@ parse_event_notifications_list(t_configuration_options *options, const char *arg static void -clear_event_notification_list(t_configuration_options *options) +clear_event_notification_list(EventNotificationList *event_notifications) { - if (options->event_notifications.head != NULL) + if (event_notifications->head != NULL) { EventNotificationListCell *cell; EventNotificationListCell *next_cell; - cell = options->event_notifications.head; + cell = event_notifications->head; while (cell != NULL) { @@ -2365,6 +2880,35 @@ print_connection_check_type(ConnectionCheckType type) +char * +print_event_notification_list(EventNotificationList *list) +{ + PQExpBufferData buf; + char *ptr; + EventNotificationListCell *cell; + + initPQExpBuffer(&buf); + cell = list->head; + + while (cell != NULL) + { + appendPQExpBufferStr(&buf, cell->event_type); + + if (cell->next) + appendPQExpBufferStr(&buf, ", "); + + cell = cell->next; + } + + ptr = palloc0(strlen(buf.data) + 1); + strncpy(ptr, buf.data, strlen(buf.data)); + + termPQExpBuffer(&buf); + + return ptr; +} + + const char * format_failover_mode(failover_mode_opt failover) diff --git a/configfile.h b/configfile.h index 96854ea5..4b76cea4 100644 --- a/configfile.h +++ b/configfile.h @@ -78,6 +78,42 @@ typedef struct TablespaceList } TablespaceList; +typedef enum +{ + CONFIG_BOOL, + CONFIG_INT, + CONFIG_STRING, + CONFIG_FAILOVER_MODE, + CONFIG_CONNECTION_CHECK_TYPE, + CONFIG_EVENT_NOTIFICATION_LIST +} ConfigItemType; + + +typedef struct ConfigFileOption +{ + const char *name; + ConfigItemType type; + union + { + int *intptr; + char *strptr; + bool *boolptr; + failover_mode_opt *failovermodeptr; + ConnectionCheckType *checktypeptr; + EventNotificationList *notificationlistptr; + } val; + union { + int intdefault; + const char *strdefault; + bool booldefault; + failover_mode_opt failovermodedefault; + ConnectionCheckType *checktypedefault; + EventNotificationList *notificationlistdefault; + } defval; + int minval; + int strmaxlen; +} ConfigFileOption; + typedef struct { /* node information */ @@ -251,8 +287,9 @@ extern t_configuration_options config_file_options; "", "", \ /* undocumented test settings */ \ 0 \ - } +} +extern t_configuration_options config_file_options; typedef struct @@ -320,9 +357,12 @@ void set_progname(const char *argv0); const char *progname(void); void load_config(const char *config_file, bool verbose, bool terse, t_configuration_options *options, char *argv0); +void load_config2(const char *config_file, bool verbose, bool terse, char *argv0); + bool reload_config(t_server_type server_type); void parse_configuration_item(t_configuration_options *options, ItemList *error_list, ItemList *warning_list, const char *name, const char *value); +void parse_configuration_item2(ItemList *error_list, ItemList *warning_list, const char *name, const char *value); bool parse_recovery_conf(const char *data_dir, t_recovery_conf *conf); @@ -346,13 +386,17 @@ const char *format_failover_mode(failover_mode_opt failover); /* called by repmgr-client and repmgrd */ void exit_with_cli_errors(ItemList *error_list, const char *repmgr_command); + void print_item_list(ItemList *item_list); const char *print_connection_check_type(ConnectionCheckType type); +char *print_event_notification_list(EventNotificationList *list); extern bool modify_auto_conf(const char *data_dir, KeyValueList *items); extern bool ProcessRepmgrConfigFile(const char *config_file, const char *base_dir, t_configuration_options *options, ItemList *error_list, ItemList *warning_list); +extern bool ProcessRepmgrConfigFile2(const char *config_file, const char *base_dir, ItemList *error_list, ItemList *warning_list); + extern bool ProcessPostgresConfigFile(const char *config_file, const char *base_dir, KeyValueList *contents, ItemList *error_list, ItemList *warning_list); #endif /* _REPMGR_CONFIGFILE_H_ */ diff --git a/repmgr-client.c b/repmgr-client.c index 70df0237..5c9caaeb 100644 --- a/repmgr-client.c +++ b/repmgr-client.c @@ -76,6 +76,7 @@ t_runtime_options runtime_options = T_RUNTIME_OPTIONS_INITIALIZER; + /* conninfo params for the node we're operating on */ t_conninfo_param_list source_conninfo = T_CONNINFO_PARAM_LIST_INITIALIZER; @@ -1073,12 +1074,11 @@ main(int argc, char **argv) * clone'), however if available we'll parse it anyway for options like * 'log_level', 'use_replication_slots' etc. */ - load_config(runtime_options.config_file, - runtime_options.verbose, - runtime_options.terse, - &config_file_options, - argv[0]); - + load_config2(runtime_options.config_file, + runtime_options.verbose, + runtime_options.terse, + argv[0]); + exit(0); check_cli_parameters(action); /*