Improve configuration file parsing

Related to Github #127.

- use the previously introduced repmgr_atoi() function to parse
  integers better
- collate all detected errors and output as a list, rather than
  failing on the first error.
This commit is contained in:
Ian Barwick
2015-11-09 14:53:11 +09:00
parent 8e66e4811c
commit abb02cab76
5 changed files with 207 additions and 170 deletions

187
config.c
View File

@@ -26,10 +26,25 @@
static void parse_event_notifications_list(t_configuration_options *options, const char *arg); static void parse_event_notifications_list(t_configuration_options *options, const char *arg);
static void tablespace_list_append(t_configuration_options *options, const char *arg); static void tablespace_list_append(t_configuration_options *options, const char *arg);
static void exit_with_errors(ErrorList *config_errors);
const static char *_progname = '\0';
static char config_file_path[MAXPGPATH]; static char config_file_path[MAXPGPATH];
static bool config_file_provided = false; static bool config_file_provided = false;
void
set_progname(const char *argv0)
{
_progname = get_progname(argv0);
}
const char *
progname(void)
{
return _progname;
}
/* /*
* load_config() * load_config()
* *
@@ -45,6 +60,7 @@ bool
load_config(const char *config_file, t_configuration_options *options, char *argv0) load_config(const char *config_file, t_configuration_options *options, char *argv0)
{ {
struct stat config; struct stat config;
/* Sanity checks */ /* Sanity checks */
/* /*
@@ -101,7 +117,13 @@ load_config(const char *config_file, t_configuration_options *options, char *arg
return parse_config(options); return parse_config(options);
} }
/*
* Parse configuration file; if any errors are encountered,
* list them and exit.
*
* Ensure any default values set here are synced with repmgr.conf.sample
* and any other documentation.
*/
bool bool
parse_config(t_configuration_options *options) parse_config(t_configuration_options *options)
{ {
@@ -115,6 +137,9 @@ parse_config(t_configuration_options *options)
PQconninfoOption *conninfo_options; PQconninfoOption *conninfo_options;
char *conninfo_errmsg = NULL; char *conninfo_errmsg = NULL;
/* Collate configuration file errors here for friendlier reporting */
static ErrorList config_errors = { NULL, NULL };
fp = fopen(config_file_path, "r"); fp = fopen(config_file_path, "r");
/* /*
@@ -177,7 +202,6 @@ parse_config(t_configuration_options *options)
options->tablespace_mapping.tail = NULL; options->tablespace_mapping.tail = NULL;
/* Read next line */ /* Read next line */
while ((s = fgets(buff, sizeof buff, fp)) != NULL) while ((s = fgets(buff, sizeof buff, fp)) != NULL)
{ {
@@ -198,9 +222,9 @@ parse_config(t_configuration_options *options)
if (strcmp(name, "cluster") == 0) if (strcmp(name, "cluster") == 0)
strncpy(options->cluster_name, value, MAXLEN); strncpy(options->cluster_name, value, MAXLEN);
else if (strcmp(name, "node") == 0) else if (strcmp(name, "node") == 0)
options->node = repmgr_atoi(value, "node", NULL); options->node = repmgr_atoi(value, "node", &config_errors);
else if (strcmp(name, "upstream_node") == 0) else if (strcmp(name, "upstream_node") == 0)
options->upstream_node = repmgr_atoi(value, "upstream_node", NULL); options->upstream_node = repmgr_atoi(value, "upstream_node", &config_errors);
else if (strcmp(name, "conninfo") == 0) else if (strcmp(name, "conninfo") == 0)
strncpy(options->conninfo, value, MAXLEN); strncpy(options->conninfo, value, MAXLEN);
else if (strcmp(name, "rsync_options") == 0) else if (strcmp(name, "rsync_options") == 0)
@@ -232,7 +256,7 @@ parse_config(t_configuration_options *options)
} }
} }
else if (strcmp(name, "priority") == 0) else if (strcmp(name, "priority") == 0)
options->priority = repmgr_atoi(value, "priority", NULL); options->priority = repmgr_atoi(value, "priority", &config_errors);
else if (strcmp(name, "node_name") == 0) else if (strcmp(name, "node_name") == 0)
strncpy(options->node_name, value, MAXLEN); strncpy(options->node_name, value, MAXLEN);
else if (strcmp(name, "promote_command") == 0) else if (strcmp(name, "promote_command") == 0)
@@ -240,16 +264,16 @@ parse_config(t_configuration_options *options)
else if (strcmp(name, "follow_command") == 0) else if (strcmp(name, "follow_command") == 0)
strncpy(options->follow_command, value, MAXLEN); strncpy(options->follow_command, value, MAXLEN);
else if (strcmp(name, "master_response_timeout") == 0) else if (strcmp(name, "master_response_timeout") == 0)
options->master_response_timeout = repmgr_atoi(value, "master_response_timeout", NULL); options->master_response_timeout = repmgr_atoi(value, "master_response_timeout", &config_errors);
/* 'primary_response_timeout' as synonym for 'master_response_timeout' - /* 'primary_response_timeout' as synonym for 'master_response_timeout' -
* we'll switch terminology in a future release (3.1?) * we'll switch terminology in a future release (3.1?)
*/ */
else if (strcmp(name, "primary_response_timeout") == 0) else if (strcmp(name, "primary_response_timeout") == 0)
options->master_response_timeout = repmgr_atoi(value, "primary_response_timeout", NULL); options->master_response_timeout = repmgr_atoi(value, "primary_response_timeout", &config_errors);
else if (strcmp(name, "reconnect_attempts") == 0) else if (strcmp(name, "reconnect_attempts") == 0)
options->reconnect_attempts = repmgr_atoi(value, "reconnect_attempts", NULL); options->reconnect_attempts = repmgr_atoi(value, "reconnect_attempts", &config_errors);
else if (strcmp(name, "reconnect_interval") == 0) else if (strcmp(name, "reconnect_interval") == 0)
options->reconnect_interval = repmgr_atoi(value, "reconnect_interval", NULL); options->reconnect_interval = repmgr_atoi(value, "reconnect_interval", &config_errors);
else if (strcmp(name, "pg_bindir") == 0) else if (strcmp(name, "pg_bindir") == 0)
strncpy(options->pg_bindir, value, MAXLEN); strncpy(options->pg_bindir, value, MAXLEN);
else if (strcmp(name, "pg_ctl_options") == 0) else if (strcmp(name, "pg_ctl_options") == 0)
@@ -259,12 +283,12 @@ parse_config(t_configuration_options *options)
else if (strcmp(name, "logfile") == 0) else if (strcmp(name, "logfile") == 0)
strncpy(options->logfile, value, MAXLEN); strncpy(options->logfile, value, MAXLEN);
else if (strcmp(name, "monitor_interval_secs") == 0) else if (strcmp(name, "monitor_interval_secs") == 0)
options->monitor_interval_secs = repmgr_atoi(value, "monitor_interval_secs", NULL); options->monitor_interval_secs = repmgr_atoi(value, "monitor_interval_secs", &config_errors);
else if (strcmp(name, "retry_promote_interval_secs") == 0) else if (strcmp(name, "retry_promote_interval_secs") == 0)
options->retry_promote_interval_secs = repmgr_atoi(value, "retry_promote_interval_secs", NULL); options->retry_promote_interval_secs = repmgr_atoi(value, "retry_promote_interval_secs", &config_errors);
else if (strcmp(name, "use_replication_slots") == 0) else if (strcmp(name, "use_replication_slots") == 0)
/* XXX we should have a dedicated boolean argument format */ /* XXX we should have a dedicated boolean argument format */
options->use_replication_slots = repmgr_atoi(value, "use_replication_slots", NULL); options->use_replication_slots = repmgr_atoi(value, "use_replication_slots", &config_errors);
else if (strcmp(name, "event_notification_command") == 0) else if (strcmp(name, "event_notification_command") == 0)
strncpy(options->event_notification_command, value, MAXLEN); strncpy(options->event_notification_command, value, MAXLEN);
else if (strcmp(name, "event_notifications") == 0) else if (strcmp(name, "event_notifications") == 0)
@@ -284,8 +308,13 @@ parse_config(t_configuration_options *options)
* as currently e.g. an empty `node` value will be converted to '0'. * as currently e.g. an empty `node` value will be converted to '0'.
*/ */
if (known_parameter == true && !strlen(value)) { if (known_parameter == true && !strlen(value)) {
log_err(_("no value provided for parameter '%s'\n"), name); char error_message_buf[MAXLEN] = "";
exit(ERR_BAD_CONFIG); snprintf(error_message_buf,
MAXLEN,
_("no value provided for parameter \"%s\""),
name);
error_list_append(&config_errors, error_message_buf);
} }
} }
@@ -296,66 +325,51 @@ parse_config(t_configuration_options *options)
/* The following checks are for the presence of the parameter */ /* The following checks are for the presence of the parameter */
if (*options->cluster_name == '\0') if (*options->cluster_name == '\0')
{ {
log_err(_("required parameter 'cluster' was not found\n")); error_list_append(&config_errors, _("\"cluster\": parameter was not found\n"));
exit(ERR_BAD_CONFIG);
} }
if (options->node == -1) if (options->node == -1)
{ {
log_err(_("required parameter 'node' was not found\n")); error_list_append(&config_errors, _("\"node\": parameter was not found\n"));
exit(ERR_BAD_CONFIG);
}
if (options->node <= 0)
{
log_err(_("'node' must be an integer greater than zero\n"));
exit(ERR_BAD_CONFIG);
} }
if (*options->node_name == '\0') if (*options->node_name == '\0')
{ {
log_err(_("required parameter 'node_name' was not found\n")); error_list_append(&config_errors, _("\"node_name\": parameter was not found\n"));
exit(ERR_BAD_CONFIG);
} }
if (*options->conninfo == '\0') if (*options->conninfo == '\0')
{ {
log_err(_("required parameter 'conninfo' was not found\n")); error_list_append(&config_errors, _("\"conninfo\": parameter was not found\n"));
exit(ERR_BAD_CONFIG);
} }
else
/* Sanity check the provided conninfo string
*
* NOTE: this verifies the string format and checks for valid options
* but does not sanity check values
*/
conninfo_options = PQconninfoParse(options->conninfo, &conninfo_errmsg);
if (conninfo_options == NULL)
{ {
log_err(_("Parameter 'conninfo' is invalid: %s"), conninfo_errmsg);
exit(ERR_BAD_CONFIG);
}
PQconninfoFree(conninfo_options);
/* The following checks are for valid parameter values */ /* Sanity check the provided conninfo string
if (options->master_response_timeout <= 0) *
* NOTE: this verifies the string format and checks for valid options
* but does not sanity check values
*/
conninfo_options = PQconninfoParse(options->conninfo, &conninfo_errmsg);
if (conninfo_options == NULL)
{
char error_message_buf[MAXLEN] = "";
snprintf(error_message_buf,
MAXLEN,
_("\"conninfo\": %s"),
conninfo_errmsg);
error_list_append(&config_errors, error_message_buf);
}
PQconninfoFree(conninfo_options);
}
// exit_with_errors here
if (config_errors.head != NULL)
{ {
log_err(_("'master_response_timeout' must be greater than zero\n")); exit_with_errors(&config_errors);
exit(ERR_BAD_CONFIG);
} }
if (options->reconnect_attempts < 0)
{
log_err(_("'reconnect_attempts' must be zero or greater\n"));
exit(ERR_BAD_CONFIG);
}
if (options->reconnect_interval < 0)
{
log_err(_("'reconnect_interval' must be zero or greater\n"));
exit(ERR_BAD_CONFIG);
}
return true; return true;
} }
@@ -675,13 +689,42 @@ reload_config(t_configuration_options *orig_options)
} }
void
error_list_append(ErrorList *error_list, char *error_message)
{
ErrorListCell *cell;
cell = (ErrorListCell *) pg_malloc0(sizeof(ErrorListCell));
if (cell == NULL)
{
log_err(_("unable to allocate memory; terminating.\n"));
exit(ERR_BAD_CONFIG);
}
cell->error_message = pg_malloc0(MAXLEN);
strncpy(cell->error_message, error_message, MAXLEN);
if (error_list->tail)
{
error_list->tail->next = cell;
}
else
{
error_list->head = cell;
}
error_list->tail = cell;
}
/* /*
* Convert provided string to an integer using strtol; * Convert provided string to an integer using strtol;
* on error, if a callback is provided, pass the error message to that, * on error, if a callback is provided, pass the error message to that,
* otherwise exit * otherwise exit
*/ */
int int
repmgr_atoi(const char *value, const char *config_item, void (*error_callback)(char *error_message)) repmgr_atoi(const char *value, const char *config_item, ErrorList *error_list)
{ {
char *endptr; char *endptr;
long longval = 0; long longval = 0;
@@ -695,7 +738,7 @@ repmgr_atoi(const char *value, const char *config_item, void (*error_callback)(c
{ {
snprintf(error_message_buf, snprintf(error_message_buf,
MAXLEN, MAXLEN,
_("No value provided for \"%s\""), _("no value provided for \"%s\""),
config_item); config_item);
} }
else else
@@ -707,7 +750,7 @@ repmgr_atoi(const char *value, const char *config_item, void (*error_callback)(c
{ {
snprintf(error_message_buf, snprintf(error_message_buf,
MAXLEN, MAXLEN,
_("Invalid value provided for \"%s\": %s"), _("\"%s\": invalid value (provided: \"%s\")"),
config_item, value); config_item, value);
} }
} }
@@ -717,20 +760,20 @@ repmgr_atoi(const char *value, const char *config_item, void (*error_callback)(c
{ {
snprintf(error_message_buf, snprintf(error_message_buf,
MAXLEN, MAXLEN,
_("\"%s\" cannot be a negative value (provided: %s)"), _("\"%s\" must be zero or greater (provided: %s)"),
config_item, value); config_item, value);
} }
/* Error message buffer is set */ /* Error message buffer is set */
if (error_message_buf[0] != '\0') if (error_message_buf[0] != '\0')
{ {
if (error_callback == NULL) if (error_list == NULL)
{ {
log_err("%s\n", error_message_buf); log_err("%s\n", error_message_buf);
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
error_callback(error_message_buf); error_list_append(error_list, error_message_buf);
} }
return (int32) longval; return (int32) longval;
@@ -868,3 +911,21 @@ parse_event_notifications_list(t_configuration_options *options, const char *arg
} }
} }
} }
static void
exit_with_errors(ErrorList *config_errors)
{
ErrorListCell *cell;
log_err(_("%s: following errors were found in the configuration file.\n"), progname());
for (cell = config_errors->head; cell; cell = cell->next)
{
log_err("%s\n", cell->error_message);
}
exit(ERR_BAD_CONFIG);
}

View File

@@ -82,14 +82,29 @@ typedef struct
#define T_CONFIGURATION_OPTIONS_INITIALIZER { "", -1, NO_UPSTREAM_NODE, "", MANUAL_FAILOVER, -1, "", "", "", "", "", "", "", -1, -1, -1, "", "", "", "", 0, 0, 0, "", { NULL, NULL }, {NULL, NULL} } #define T_CONFIGURATION_OPTIONS_INITIALIZER { "", -1, NO_UPSTREAM_NODE, "", MANUAL_FAILOVER, -1, "", "", "", "", "", "", "", -1, -1, -1, "", "", "", "", 0, 0, 0, "", { NULL, NULL }, {NULL, NULL} }
typedef struct ErrorListCell
{
struct ErrorListCell *next;
char *error_message;
} ErrorListCell;
typedef struct ErrorList
{
ErrorListCell *head;
ErrorListCell *tail;
} ErrorList;
void set_progname(const char *argv0);
const char * progname(void);
bool load_config(const char *config_file, t_configuration_options *options, char *argv0); bool load_config(const char *config_file, t_configuration_options *options, char *argv0);
bool reload_config(t_configuration_options *orig_options); bool reload_config(t_configuration_options *orig_options);
bool parse_config(t_configuration_options *options); bool parse_config(t_configuration_options *options);
void parse_line(char *buff, char *name, char *value); void parse_line(char *buff, char *name, char *value);
char *trim(char *s); char *trim(char *s);
void error_list_append(ErrorList *error_list, char *error_message);
int repmgr_atoi(const char *s, int repmgr_atoi(const char *s,
const char *config_item, const char *config_item,
void (*error_callback)(char *error_message)); ErrorList *error_list);
#endif #endif

133
repmgr.c
View File

@@ -101,12 +101,11 @@ static void do_cluster_show(void);
static void do_cluster_cleanup(void); static void do_cluster_cleanup(void);
static void do_check_upstream_config(void); static void do_check_upstream_config(void);
static void error_list_append(char *error_message);
static void exit_with_errors(void); static void exit_with_errors(void);
static void help(const char *progname); static void help(void);
/* Global variables */ /* Global variables */
static const char *progname; //static const char *progname;
static const char *keywords[6]; static const char *keywords[6];
static const char *values[6]; static const char *values[6];
static bool config_file_required = true; static bool config_file_required = true;
@@ -127,7 +126,8 @@ static char *repmgr_slot_name_ptr = NULL;
static char path_buf[MAXLEN] = ""; static char path_buf[MAXLEN] = "";
/* Collate command line errors here for friendlier reporting */ /* Collate command line errors here for friendlier reporting */
static ErrorList cli_errors = { NULL, NULL }; ErrorList cli_errors = { NULL, NULL };
int int
main(int argc, char **argv) main(int argc, char **argv)
@@ -168,7 +168,8 @@ main(int argc, char **argv)
bool config_file_parsed = false; bool config_file_parsed = false;
char *ptr = NULL; char *ptr = NULL;
progname = get_progname(argv[0]); set_progname(argv[0]);
/* Prevent getopt_long() from printing an error message */ /* Prevent getopt_long() from printing an error message */
opterr = 0; opterr = 0;
@@ -179,16 +180,16 @@ main(int argc, char **argv)
/* /*
* NOTE: some integer parameters (e.g. -p/--port) are stored internally * NOTE: some integer parameters (e.g. -p/--port) are stored internally
* as strings. We use repmgr_atoi() to check these but discard the * as strings. We use repmgr_atoi() to check these but discard the
* returned integer; the callback passed to repmgr_atoi() will append the * returned integer; repmgr_atoi() will append the error message to the
* error message to the list. * provided list.
*/ */
switch (c) switch (c)
{ {
case '?': case '?':
help(progname); help();
exit(SUCCESS); exit(SUCCESS);
case 'V': case 'V':
printf("%s %s (PostgreSQL %s)\n", progname, REPMGR_VERSION, PG_VERSION); printf("%s %s (PostgreSQL %s)\n", progname(), REPMGR_VERSION, PG_VERSION);
exit(SUCCESS); exit(SUCCESS);
case 'd': case 'd':
strncpy(runtime_options.dbname, optarg, MAXLEN); strncpy(runtime_options.dbname, optarg, MAXLEN);
@@ -197,7 +198,7 @@ main(int argc, char **argv)
strncpy(runtime_options.host, optarg, MAXLEN); strncpy(runtime_options.host, optarg, MAXLEN);
break; break;
case 'p': case 'p':
repmgr_atoi(optarg, "-p/--port", error_list_append); repmgr_atoi(optarg, "-p/--port", &cli_errors);
strncpy(runtime_options.masterport, strncpy(runtime_options.masterport,
optarg, optarg,
MAXLEN); MAXLEN);
@@ -213,7 +214,7 @@ main(int argc, char **argv)
break; break;
case 'l': case 'l':
/* -l/--local-port is deprecated */ /* -l/--local-port is deprecated */
repmgr_atoi(optarg, "-l/--local-port", error_list_append); repmgr_atoi(optarg, "-l/--local-port", &cli_errors);
strncpy(runtime_options.localport, strncpy(runtime_options.localport,
optarg, optarg,
MAXLEN); MAXLEN);
@@ -225,14 +226,14 @@ main(int argc, char **argv)
strncpy(runtime_options.remote_user, optarg, MAXLEN); strncpy(runtime_options.remote_user, optarg, MAXLEN);
break; break;
case 'w': case 'w':
repmgr_atoi(optarg, "-w/--wal-keep-segments", error_list_append); repmgr_atoi(optarg, "-w/--wal-keep-segments", &cli_errors);
strncpy(runtime_options.wal_keep_segments, strncpy(runtime_options.wal_keep_segments,
optarg, optarg,
MAXLEN); MAXLEN);
wal_keep_segments_used = true; wal_keep_segments_used = true;
break; break;
case 'k': case 'k':
runtime_options.keep_history = repmgr_atoi(optarg, "-k/--keep-history", error_list_append); runtime_options.keep_history = repmgr_atoi(optarg, "-k/--keep-history", &cli_errors);
break; break;
case 'F': case 'F':
runtime_options.force = true; runtime_options.force = true;
@@ -266,7 +267,7 @@ main(int argc, char **argv)
if (targ < 1) if (targ < 1)
{ {
error_list_append(_("Invalid value provided for '-r/--recovery-min-apply-delay'")); error_list_append(&cli_errors, _("Invalid value provided for '-r/--recovery-min-apply-delay'"));
break; break;
} }
if (ptr && *ptr) if (ptr && *ptr)
@@ -275,7 +276,7 @@ main(int argc, char **argv)
strcmp(ptr, "min") != 0 && strcmp(ptr, "h") != 0 && strcmp(ptr, "min") != 0 && strcmp(ptr, "h") != 0 &&
strcmp(ptr, "d") != 0) strcmp(ptr, "d") != 0)
{ {
error_list_append(_("Value provided for '-r/--recovery-min-apply-delay' must be one of ms/s/min/h/d")); error_list_append(&cli_errors, _("Value provided for '-r/--recovery-min-apply-delay' must be one of ms/s/min/h/d"));
break; break;
} }
} }
@@ -291,7 +292,7 @@ main(int argc, char **argv)
initPQExpBuffer(&unknown_option); initPQExpBuffer(&unknown_option);
appendPQExpBuffer(&unknown_option, _("Unknown option '%s'"), argv[optind - 1]); appendPQExpBuffer(&unknown_option, _("Unknown option '%s'"), argv[optind - 1]);
error_list_append(unknown_option.data); error_list_append(&cli_errors, unknown_option.data);
} }
} }
} }
@@ -333,7 +334,7 @@ main(int argc, char **argv)
PQExpBufferData unknown_mode; PQExpBufferData unknown_mode;
initPQExpBuffer(&unknown_mode); initPQExpBuffer(&unknown_mode);
appendPQExpBuffer(&unknown_mode, _("Unknown server mode '%s'"), server_mode); appendPQExpBuffer(&unknown_mode, _("Unknown server mode '%s'"), server_mode);
error_list_append(unknown_mode.data); error_list_append(&cli_errors, unknown_mode.data);
} }
} }
@@ -376,14 +377,14 @@ main(int argc, char **argv)
if (action == NO_ACTION) { if (action == NO_ACTION) {
if (server_cmd == NULL) if (server_cmd == NULL)
{ {
error_list_append("No server command provided"); error_list_append(&cli_errors, "No server command provided");
} }
else else
{ {
PQExpBufferData unknown_action; PQExpBufferData unknown_action;
initPQExpBuffer(&unknown_action); initPQExpBuffer(&unknown_action);
appendPQExpBuffer(&unknown_action, _("Unknown server command '%s'"), server_cmd); appendPQExpBuffer(&unknown_action, _("Unknown server command '%s'"), server_cmd);
error_list_append(unknown_action.data); error_list_append(&cli_errors, unknown_action.data);
} }
} }
@@ -394,7 +395,7 @@ main(int argc, char **argv)
{ {
if (runtime_options.host[0]) if (runtime_options.host[0])
{ {
error_list_append(_("Conflicting parameters: you can't use -h while providing a node separately.")); error_list_append(&cli_errors, _("Conflicting parameters: you can't use -h while providing a node separately."));
} }
else else
{ {
@@ -408,7 +409,7 @@ main(int argc, char **argv)
PQExpBufferData too_many_args; PQExpBufferData too_many_args;
initPQExpBuffer(&too_many_args); initPQExpBuffer(&too_many_args);
appendPQExpBuffer(&too_many_args, _("too many command-line arguments (first extra is \"%s\")"), argv[optind]); appendPQExpBuffer(&too_many_args, _("too many command-line arguments (first extra is \"%s\")"), argv[optind]);
error_list_append(too_many_args.data); error_list_append(&cli_errors, too_many_args.data);
} }
check_parameters_for_action(action); check_parameters_for_action(action);
@@ -483,7 +484,7 @@ main(int argc, char **argv)
keywords[3] = "dbname"; keywords[3] = "dbname";
values[3] = runtime_options.dbname; values[3] = runtime_options.dbname;
keywords[4] = "application_name"; keywords[4] = "application_name";
values[4] = (char *) progname; values[4] = (char *) progname();
keywords[5] = NULL; keywords[5] = NULL;
values[5] = NULL; values[5] = NULL;
@@ -494,7 +495,7 @@ main(int argc, char **argv)
* logging level might be specified at, but it often requires detailed * logging level might be specified at, but it often requires detailed
* logging to troubleshoot problems. * logging to troubleshoot problems.
*/ */
logger_init(&options, progname, options.loglevel, options.logfacility); logger_init(&options, progname(), options.loglevel, options.logfacility);
if (runtime_options.verbose) if (runtime_options.verbose)
logger_min_verbose(LOG_INFO); logger_min_verbose(LOG_INFO);
@@ -2197,7 +2198,7 @@ do_witness_create(void)
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }
xsnprintf(buf, sizeof(buf), "\n#Configuration added by %s\n", progname); xsnprintf(buf, sizeof(buf), "\n#Configuration added by %s\n", progname());
fputs(buf, pg_conf); fputs(buf, pg_conf);
@@ -2488,15 +2489,15 @@ do_witness_create(void)
static void static void
help(const char *progname) help(void)
{ {
printf(_("%s: replication management tool for PostgreSQL\n"), progname); printf(_("%s: replication management tool for PostgreSQL\n"), progname());
printf(_("\n")); printf(_("\n"));
printf(_("Usage:\n")); printf(_("Usage:\n"));
printf(_(" %s [OPTIONS] master {register}\n"), progname); printf(_(" %s [OPTIONS] master {register}\n"), progname());
printf(_(" %s [OPTIONS] standby {register|unregister|clone|promote|follow}\n"), printf(_(" %s [OPTIONS] standby {register|unregister|clone|promote|follow}\n"),
progname); progname());
printf(_(" %s [OPTIONS] cluster {show|cleanup}\n"), progname); printf(_(" %s [OPTIONS] cluster {show|cleanup}\n"), progname());
printf(_("\n")); printf(_("\n"));
printf(_("General options:\n")); printf(_("General options:\n"));
printf(_(" -?, --help show this help, then exit\n")); printf(_(" -?, --help show this help, then exit\n"));
@@ -2538,7 +2539,7 @@ help(const char *progname)
printf(_(" -S, --superuser=USERNAME (witness server) superuser username for witness database\n" \ printf(_(" -S, --superuser=USERNAME (witness server) superuser username for witness database\n" \
" (default: postgres)\n")); " (default: postgres)\n"));
printf(_("\n")); printf(_("\n"));
printf(_("%s performs the following node management tasks:\n"), progname); printf(_("%s performs the following node management tasks:\n"), progname());
printf(_("\n")); printf(_("\n"));
printf(_("COMMANDS:\n")); printf(_("COMMANDS:\n"));
printf(_(" master register - registers the master in a cluster\n")); printf(_(" master register - registers the master in a cluster\n"));
@@ -2855,11 +2856,11 @@ check_parameters_for_action(const int action)
if (runtime_options.host[0] || runtime_options.masterport[0] || if (runtime_options.host[0] || runtime_options.masterport[0] ||
runtime_options.username[0] || runtime_options.dbname[0]) runtime_options.username[0] || runtime_options.dbname[0])
{ {
error_list_append(_("master connection parameters not required when executing MASTER REGISTER")); error_list_append(&cli_errors, _("master connection parameters not required when executing MASTER REGISTER"));
} }
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
error_list_append(_("destination directory not required when executing MASTER REGISTER")); error_list_append(&cli_errors, _("destination directory not required when executing MASTER REGISTER"));
} }
break; break;
case STANDBY_REGISTER: case STANDBY_REGISTER:
@@ -2872,11 +2873,11 @@ check_parameters_for_action(const int action)
if (runtime_options.host[0] || runtime_options.masterport[0] || if (runtime_options.host[0] || runtime_options.masterport[0] ||
runtime_options.username[0] || runtime_options.dbname[0]) runtime_options.username[0] || runtime_options.dbname[0])
{ {
error_list_append(_("master connection parameters not required when executing STANDBY REGISTER")); error_list_append(&cli_errors, _("master connection parameters not required when executing STANDBY REGISTER"));
} }
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
error_list_append(_("destination directory not required when executing STANDBY REGISTER")); error_list_append(&cli_errors, _("destination directory not required when executing STANDBY REGISTER"));
} }
break; break;
case STANDBY_UNREGISTER: case STANDBY_UNREGISTER:
@@ -2889,11 +2890,11 @@ check_parameters_for_action(const int action)
if (runtime_options.host[0] || runtime_options.masterport[0] || if (runtime_options.host[0] || runtime_options.masterport[0] ||
runtime_options.username[0] || runtime_options.dbname[0]) runtime_options.username[0] || runtime_options.dbname[0])
{ {
error_list_append(_("master connection parameters not required when executing STANDBY UNREGISTER")); error_list_append(&cli_errors, _("master connection parameters not required when executing STANDBY UNREGISTER"));
} }
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
error_list_append(_("destination directory not required when executing STANDBY UNREGISTER")); error_list_append(&cli_errors, _("destination directory not required when executing STANDBY UNREGISTER"));
} }
break; break;
case STANDBY_PROMOTE: case STANDBY_PROMOTE:
@@ -2907,11 +2908,11 @@ check_parameters_for_action(const int action)
if (runtime_options.host[0] || runtime_options.masterport[0] || if (runtime_options.host[0] || runtime_options.masterport[0] ||
runtime_options.username[0] || runtime_options.dbname[0]) runtime_options.username[0] || runtime_options.dbname[0])
{ {
error_list_append(_("master connection parameters not required when executing STANDBY PROMOTE")); error_list_append(&cli_errors, _("master connection parameters not required when executing STANDBY PROMOTE"));
} }
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
error_list_append(_("destination directory not required when executing STANDBY PROMOTE")); error_list_append(&cli_errors, _("destination directory not required when executing STANDBY PROMOTE"));
} }
break; break;
case STANDBY_FOLLOW: case STANDBY_FOLLOW:
@@ -2925,11 +2926,11 @@ check_parameters_for_action(const int action)
if (runtime_options.host[0] || runtime_options.masterport[0] || if (runtime_options.host[0] || runtime_options.masterport[0] ||
runtime_options.username[0] || runtime_options.dbname[0]) runtime_options.username[0] || runtime_options.dbname[0])
{ {
error_list_append(_("master connection parameters not required when executing STANDBY FOLLOW")); error_list_append(&cli_errors, _("master connection parameters not required when executing STANDBY FOLLOW"));
} }
if (runtime_options.dest_dir[0]) if (runtime_options.dest_dir[0])
{ {
error_list_append(_("destination directory not required when executing STANDBY FOLLOW")); error_list_append(&cli_errors, _("destination directory not required when executing STANDBY FOLLOW"));
} }
break; break;
case STANDBY_CLONE: case STANDBY_CLONE:
@@ -2942,17 +2943,17 @@ check_parameters_for_action(const int action)
if (strcmp(runtime_options.host, "") == 0) if (strcmp(runtime_options.host, "") == 0)
{ {
error_list_append(_("master hostname (-h/--host) required when executing STANDBY CLONE")); error_list_append(&cli_errors, _("master hostname (-h/--host) required when executing STANDBY CLONE"));
} }
if (strcmp(runtime_options.dbname, "") == 0) if (strcmp(runtime_options.dbname, "") == 0)
{ {
error_list_append(_("master database name (-d/--dbname) required when executing STANDBY CLONE")); error_list_append(&cli_errors, _("master database name (-d/--dbname) required when executing STANDBY CLONE"));
} }
if (strcmp(runtime_options.username, "") == 0) if (strcmp(runtime_options.username, "") == 0)
{ {
error_list_append(_("master database username (-U/--username) required when executing STANDBY CLONE")); error_list_append(&cli_errors, _("master database username (-U/--username) required when executing STANDBY CLONE"));
} }
config_file_required = false; config_file_required = false;
@@ -2972,22 +2973,22 @@ check_parameters_for_action(const int action)
{ {
if (runtime_options.rsync_only) if (runtime_options.rsync_only)
{ {
error_list_append(_("--rsync-only can only be used when executing STANDBY CLONE")); error_list_append(&cli_errors, _("--rsync-only can only be used when executing STANDBY CLONE"));
} }
if (runtime_options.fast_checkpoint) if (runtime_options.fast_checkpoint)
{ {
error_list_append(_("--fast-checkpoint can only be used when executing STANDBY CLONE")); error_list_append(&cli_errors, _("--fast-checkpoint can only be used when executing STANDBY CLONE"));
} }
if (runtime_options.ignore_external_config_files) if (runtime_options.ignore_external_config_files)
{ {
error_list_append(_("--ignore-external-config-files can only be used when executing STANDBY CLONE")); error_list_append(&cli_errors, _("--ignore-external-config-files can only be used when executing STANDBY CLONE"));
} }
if (*runtime_options.recovery_min_apply_delay) if (*runtime_options.recovery_min_apply_delay)
{ {
error_list_append(_("--recovery-min-apply-delay can only be used when executing STANDBY CLONE")); error_list_append(&cli_errors, _("--recovery-min-apply-delay can only be used when executing STANDBY CLONE"));
} }
} }
@@ -3333,7 +3334,7 @@ check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *
{ {
if (server_version_num > 0) if (server_version_num > 0)
log_err(_("%s requires %s to be PostgreSQL %s or later\n"), log_err(_("%s requires %s to be PostgreSQL %s or later\n"),
progname, progname(),
server_type, server_type,
MIN_SUPPORTED_VERSION MIN_SUPPORTED_VERSION
); );
@@ -3709,48 +3710,20 @@ make_pg_path(char *file)
} }
static void
error_list_append(char *error_message)
{
ErrorListCell *cell;
cell = (ErrorListCell *) pg_malloc0(sizeof(ErrorListCell));
if (cell == NULL)
{
log_err(_("unable to allocate memory; terminating.\n"));
exit(ERR_BAD_CONFIG);
}
cell->error_message = pg_malloc0(MAXLEN);
strncpy(cell->error_message, error_message, MAXLEN);
if (cli_errors.tail)
{
cli_errors.tail->next = cell;
}
else
{
cli_errors.head = cell;
}
cli_errors.tail = cell;
}
static void static void
exit_with_errors(void) exit_with_errors(void)
{ {
ErrorListCell *cell; ErrorListCell *cell;
fprintf(stderr, _("%s: Replication manager \n"), progname); fprintf(stderr, _("%s: following command line errors were encountered.\n"), progname());
for (cell = cli_errors.head; cell; cell = cell->next) for (cell = cli_errors.head; cell; cell = cell->next)
{ {
fprintf(stderr, "[ERROR] %s\n", cell->error_message); fprintf(stderr, "%s\n", cell->error_message);
} }
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname());
exit(ERR_BAD_CONFIG); exit(ERR_BAD_CONFIG);
} }

View File

@@ -95,16 +95,5 @@ typedef struct
extern char repmgr_schema[MAXLEN]; extern char repmgr_schema[MAXLEN];
typedef struct ErrorListCell
{
struct ErrorListCell *next;
char *error_message;
} ErrorListCell;
typedef struct ErrorList
{
ErrorListCell *head;
ErrorListCell *tail;
} ErrorList;
#endif #endif

View File

@@ -68,8 +68,6 @@ t_configuration_options master_options;
PGconn *master_conn = NULL; PGconn *master_conn = NULL;
const char *progname;
char *config_file = DEFAULT_CONFIG_FILE; char *config_file = DEFAULT_CONFIG_FILE;
bool verbose = false; bool verbose = false;
bool monitoring_history = false; bool monitoring_history = false;
@@ -81,7 +79,7 @@ char *pid_file = NULL;
t_configuration_options config = T_CONFIGURATION_OPTIONS_INITIALIZER; t_configuration_options config = T_CONFIGURATION_OPTIONS_INITIALIZER;
static void help(const char *progname); static void help(void);
static void usage(void); static void usage(void);
static void check_cluster_configuration(PGconn *conn); static void check_cluster_configuration(PGconn *conn);
static void check_node_configuration(void); static void check_node_configuration(void);
@@ -158,7 +156,8 @@ main(int argc, char **argv)
FILE *fd; FILE *fd;
int server_version_num = 0; int server_version_num = 0;
progname = get_progname(argv[0]);
set_progname(argv[0]);
while ((c = getopt_long(argc, argv, "?Vf:v:mdp:", long_options, &optindex)) != -1) while ((c = getopt_long(argc, argv, "?Vf:v:mdp:", long_options, &optindex)) != -1)
{ {
@@ -180,10 +179,10 @@ main(int argc, char **argv)
pid_file = optarg; pid_file = optarg;
break; break;
case '?': case '?':
help(progname); help();
exit(SUCCESS); exit(SUCCESS);
case 'V': case 'V':
printf("%s %s (PostgreSQL %s)\n", progname, REPMGR_VERSION, PG_VERSION); printf("%s %s (PostgreSQL %s)\n", progname(), REPMGR_VERSION, PG_VERSION);
exit(SUCCESS); exit(SUCCESS);
default: default:
usage(); usage();
@@ -230,7 +229,7 @@ main(int argc, char **argv)
strerror(errno)); strerror(errno));
} }
logger_init(&local_options, progname, local_options.loglevel, logger_init(&local_options, progname(), local_options.loglevel,
local_options.logfacility); local_options.logfacility);
if (verbose) if (verbose)
logger_min_verbose(LOG_INFO); logger_min_verbose(LOG_INFO);
@@ -264,7 +263,7 @@ main(int argc, char **argv)
if (server_version_num > 0) if (server_version_num > 0)
{ {
log_err(_("%s requires PostgreSQL %s or later\n"), log_err(_("%s requires PostgreSQL %s or later\n"),
progname, progname(),
MIN_SUPPORTED_VERSION) ; MIN_SUPPORTED_VERSION) ;
} }
else else
@@ -2073,18 +2072,18 @@ lsn_to_xlogrecptr(char *lsn, bool *format_ok)
void void
usage(void) usage(void)
{ {
log_err(_("%s: Replicator manager daemon \n"), progname); log_err(_("%s: Replicator manager daemon \n"), progname());
log_err(_("Try \"%s --help\" for more information.\n"), progname); log_err(_("Try \"%s --help\" for more information.\n"), progname());
} }
void void
help(const char *progname) help(void)
{ {
printf(_("%s: replication management daemon for PostgreSQL\n"), progname); printf(_("%s: replication management daemon for PostgreSQL\n"), progname());
printf(_("\n")); printf(_("\n"));
printf(_("Usage:\n")); printf(_("Usage:\n"));
printf(_(" %s [OPTIONS]\n"), progname); printf(_(" %s [OPTIONS]\n"), progname());
printf(_("\n")); printf(_("\n"));
printf(_("Options:\n")); printf(_("Options:\n"));
printf(_(" -?, --help show this help, then exit\n")); printf(_(" -?, --help show this help, then exit\n"));
@@ -2095,7 +2094,7 @@ help(const char *progname)
printf(_(" -d, --daemonize detach process from foreground\n")); printf(_(" -d, --daemonize detach process from foreground\n"));
printf(_(" -p, --pid-file=PATH write a PID file\n")); printf(_(" -p, --pid-file=PATH write a PID file\n"));
printf(_("\n")); printf(_("\n"));
printf(_("%s monitors a cluster of servers and optionally performs failover.\n"), progname); printf(_("%s monitors a cluster of servers and optionally performs failover.\n"), progname());
} }
@@ -2133,7 +2132,7 @@ terminate(int retval)
unlink(pid_file); unlink(pid_file);
} }
log_info(_("%s terminating...\n"), progname); log_info(_("%s terminating...\n"), progname());
exit(retval); exit(retval);
} }