mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-26 08:36:30 +00:00
Refactor command line option checks
This commit is contained in:
@@ -8,3 +8,8 @@ replication, and perform administrative tasks such as failover or switchover
|
|||||||
operations.
|
operations.
|
||||||
|
|
||||||
`repmgr 4` is a complete rewrite of the existing `repmgr` codebase.
|
`repmgr 4` is a complete rewrite of the existing `repmgr` codebase.
|
||||||
|
|
||||||
|
Commands
|
||||||
|
--------
|
||||||
|
|
||||||
|
repmgr cluster event [--all] [--node-id] [--node-name] [--event] [--event-matching]
|
||||||
27
config.c
27
config.c
@@ -656,33 +656,6 @@ exit_with_errors(ItemList *config_errors, ItemList *config_warnings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
item_list_append(ItemList *item_list, char *error_message)
|
|
||||||
{
|
|
||||||
ItemListCell *cell;
|
|
||||||
|
|
||||||
cell = (ItemListCell *) pg_malloc0(sizeof(ItemListCell));
|
|
||||||
|
|
||||||
if (cell == NULL)
|
|
||||||
{
|
|
||||||
log_error(_("unable to allocate memory; terminating."));
|
|
||||||
exit(ERR_BAD_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
cell->string = pg_malloc0(MAXLEN);
|
|
||||||
strncpy(cell->string, error_message, MAXLEN);
|
|
||||||
|
|
||||||
if (item_list->tail)
|
|
||||||
{
|
|
||||||
item_list->tail->next = cell;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item_list->head = cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
item_list->tail = cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
13
config.h
13
config.h
@@ -26,18 +26,6 @@ typedef struct EventNotificationList
|
|||||||
} EventNotificationList;
|
} EventNotificationList;
|
||||||
|
|
||||||
|
|
||||||
typedef struct ItemListCell
|
|
||||||
{
|
|
||||||
struct ItemListCell *next;
|
|
||||||
char *string;
|
|
||||||
} ItemListCell;
|
|
||||||
|
|
||||||
typedef struct ItemList
|
|
||||||
{
|
|
||||||
ItemListCell *head;
|
|
||||||
ItemListCell *tail;
|
|
||||||
} ItemList;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct TablespaceListCell
|
typedef struct TablespaceListCell
|
||||||
{
|
{
|
||||||
@@ -145,7 +133,6 @@ bool load_config(const char *config_file, bool verbose, t_configuration_options
|
|||||||
bool parse_config(t_configuration_options *options);
|
bool parse_config(t_configuration_options *options);
|
||||||
bool reload_config(t_configuration_options *orig_options);
|
bool reload_config(t_configuration_options *orig_options);
|
||||||
|
|
||||||
void item_list_append(ItemList *item_list, char *error_message);
|
|
||||||
|
|
||||||
int repmgr_atoi(const char *s,
|
int repmgr_atoi(const char *s,
|
||||||
const char *config_item,
|
const char *config_item,
|
||||||
|
|||||||
164
repmgr-client.c
164
repmgr-client.c
@@ -11,6 +11,8 @@
|
|||||||
* [ MASTER | PRIMARY ] REGISTER
|
* [ MASTER | PRIMARY ] REGISTER
|
||||||
*
|
*
|
||||||
* STANDBY CLONE (wip)
|
* STANDBY CLONE (wip)
|
||||||
|
*
|
||||||
|
* CLUSTER EVENT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -58,7 +60,7 @@ main(int argc, char **argv)
|
|||||||
logger_output_mode = OM_COMMAND_LINE;
|
logger_output_mode = OM_COMMAND_LINE;
|
||||||
|
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "?Vf:vtFb:S:L:", long_options,
|
while ((c = getopt_long(argc, argv, "?Vf:Fb:S:D:L:vt", long_options,
|
||||||
&optindex)) != -1)
|
&optindex)) != -1)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -112,6 +114,10 @@ main(int argc, char **argv)
|
|||||||
strncpy(runtime_options.superuser, optarg, MAXLEN);
|
strncpy(runtime_options.superuser, optarg, MAXLEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
strncpy(runtime_options.data_dir, optarg, MAXPGPATH);
|
||||||
|
break;
|
||||||
|
|
||||||
/* logging options
|
/* logging options
|
||||||
* --------------- */
|
* --------------- */
|
||||||
|
|
||||||
@@ -182,7 +188,7 @@ main(int argc, char **argv)
|
|||||||
* STANDBY {REGISTER | UNREGISTER | CLONE [node] | PROMOTE | FOLLOW [node] | SWITCHOVER | REWIND} |
|
* STANDBY {REGISTER | UNREGISTER | CLONE [node] | PROMOTE | FOLLOW [node] | SWITCHOVER | REWIND} |
|
||||||
* WITNESS { CREATE | REGISTER | UNREGISTER } |
|
* WITNESS { CREATE | REGISTER | UNREGISTER } |
|
||||||
* BDR { REGISTER | UNREGISTER } |
|
* BDR { REGISTER | UNREGISTER } |
|
||||||
* CLUSTER { CROSSCHECK | MATRIX | SHOW | CLEANUP }
|
* CLUSTER { CROSSCHECK | MATRIX | SHOW | CLEANUP | EVENT }
|
||||||
*
|
*
|
||||||
* [node] is an optional hostname, provided instead of the -h/--host optipn
|
* [node] is an optional hostname, provided instead of the -h/--host optipn
|
||||||
*/
|
*/
|
||||||
@@ -207,6 +213,11 @@ main(int argc, char **argv)
|
|||||||
if (strcasecmp(repmgr_action, "REGISTER") == 0)
|
if (strcasecmp(repmgr_action, "REGISTER") == 0)
|
||||||
action = MASTER_REGISTER;
|
action = MASTER_REGISTER;
|
||||||
}
|
}
|
||||||
|
else if(strcasecmp(repmgr_node_type, "CLUSTER") == 0)
|
||||||
|
{
|
||||||
|
if (strcasecmp(repmgr_action, "EVENT") == 0)
|
||||||
|
action = CLUSTER_EVENT;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
valid_repmgr_node_type_found = false;
|
valid_repmgr_node_type_found = false;
|
||||||
@@ -246,6 +257,16 @@ main(int argc, char **argv)
|
|||||||
item_list_append(&cli_errors, command_error.data);
|
item_list_append(&cli_errors, command_error.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optind < argc)
|
||||||
|
{
|
||||||
|
PQExpBufferData too_many_args;
|
||||||
|
initPQExpBuffer(&too_many_args);
|
||||||
|
appendPQExpBuffer(&too_many_args, _("too many command-line arguments (first extra is \"%s\")"), argv[optind]);
|
||||||
|
item_list_append(&cli_errors, too_many_args.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_cli_parameters(action);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sanity checks for command line parameters completed by now;
|
* Sanity checks for command line parameters completed by now;
|
||||||
* any further errors will be runtime ones
|
* any further errors will be runtime ones
|
||||||
@@ -255,6 +276,15 @@ main(int argc, char **argv)
|
|||||||
exit_with_errors();
|
exit_with_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print any warnings about inappropriate command line options,
|
||||||
|
* unless -t/--terse set
|
||||||
|
*/
|
||||||
|
if (cli_warnings.head != NULL && runtime_options.terse == false)
|
||||||
|
{
|
||||||
|
log_warning(_("following problems with command line parameters detected:"));
|
||||||
|
print_item_list(&cli_warnings);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The configuration file is not required for some actions (e.g. 'standby clone'),
|
* The configuration file is not required for some actions (e.g. 'standby clone'),
|
||||||
@@ -354,6 +384,9 @@ main(int argc, char **argv)
|
|||||||
case STANDBY_CLONE:
|
case STANDBY_CLONE:
|
||||||
do_standby_clone();
|
do_standby_clone();
|
||||||
break;
|
break;
|
||||||
|
case CLUSTER_EVENT:
|
||||||
|
do_cluster_event();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* An action will have been determined by this point */
|
/* An action will have been determined by this point */
|
||||||
break;
|
break;
|
||||||
@@ -364,12 +397,96 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for useless or conflicting parameters, and also whether a
|
||||||
|
* configuration file is required.
|
||||||
|
*
|
||||||
|
* Messages will be added to the command line warning and error lists
|
||||||
|
* as appropriate.
|
||||||
|
*
|
||||||
|
* XXX for each individual actions, check only required actions
|
||||||
|
* for non-required actions check warn if provided
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_cli_parameters(const int action)
|
||||||
|
{
|
||||||
|
/* ========================================================================
|
||||||
|
* check all parameters required for an action are provided, and warn
|
||||||
|
* about ineffective actions
|
||||||
|
* ========================================================================
|
||||||
|
*/
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case MASTER_REGISTER:
|
||||||
|
/* no required parameters */
|
||||||
|
case CLUSTER_EVENT:
|
||||||
|
/* no required parameters */
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ========================================================================
|
||||||
|
* warn if parameters provided for an action where they're not relevant
|
||||||
|
* ========================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* --host etc.*/
|
||||||
|
if (runtime_options.connection_param_provided)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case STANDBY_CLONE:
|
||||||
|
case STANDBY_FOLLOW:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
item_list_append_format(&cli_warnings,
|
||||||
|
_("datqabase connection parameters not required when executing %s"),
|
||||||
|
action_name(action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -D/--data-dir */
|
||||||
|
if (runtime_options.data_dir[0])
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case STANDBY_CLONE:
|
||||||
|
case STANDBY_FOLLOW:
|
||||||
|
case STANDBY_RESTORE_CONFIG:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
item_list_append_format(&cli_warnings,
|
||||||
|
_("-D/--pgdata not required when executing %s"),
|
||||||
|
action_name(action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
action_name(const int action)
|
||||||
|
{
|
||||||
|
switch(action)
|
||||||
|
{
|
||||||
|
case MASTER_REGISTER:
|
||||||
|
return "MASTER REGISTER";
|
||||||
|
case STANDBY_CLONE:
|
||||||
|
return "STANDBY CLONE";
|
||||||
|
case CLUSTER_EVENT:
|
||||||
|
return "CLUSTER EVENT";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "UNKNOWN ACTION";
|
||||||
|
}
|
||||||
static void
|
static void
|
||||||
exit_with_errors(void)
|
exit_with_errors(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("The following command line errors were encountered:\n"));
|
fprintf(stderr, _("The following command line errors were encountered:\n"));
|
||||||
|
|
||||||
print_error_list(&cli_errors, LOG_ERR);
|
print_item_list(&cli_errors);
|
||||||
|
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname());
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname());
|
||||||
|
|
||||||
@@ -378,23 +495,13 @@ exit_with_errors(void)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_error_list(ItemList *error_list, int log_level)
|
print_item_list(ItemList *item_list)
|
||||||
{
|
{
|
||||||
ItemListCell *cell;
|
ItemListCell *cell;
|
||||||
|
|
||||||
for (cell = error_list->head; cell; cell = cell->next)
|
for (cell = item_list->head; cell; cell = cell->next)
|
||||||
{
|
{
|
||||||
fprintf(stderr, " ");
|
fprintf(stderr, " %s\n", cell->string);
|
||||||
switch(log_level)
|
|
||||||
{
|
|
||||||
/* Currently we only need errors and warnings */
|
|
||||||
case LOG_ERROR:
|
|
||||||
log_error("%s", cell->string);
|
|
||||||
break;
|
|
||||||
case LOG_WARNING:
|
|
||||||
log_warning("%s", cell->string);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,7 +700,30 @@ do_standby_clone(void)
|
|||||||
puts("standby clone");
|
puts("standby clone");
|
||||||
}
|
}
|
||||||
|
|
||||||
// this should be the only place where superuser rights required
|
|
||||||
|
/*
|
||||||
|
* CLUSTER EVENT
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* --limit[=20]
|
||||||
|
* --all
|
||||||
|
* --node_[id|name]
|
||||||
|
* --event
|
||||||
|
* --event-matching
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
do_cluster_event(void)
|
||||||
|
{
|
||||||
|
puts("cluster event");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the repmgr extension, and grant access to the repmgr
|
||||||
|
* user if not a superuser.
|
||||||
|
*
|
||||||
|
* Note: this should be the only place where superuser rights are required
|
||||||
|
*/
|
||||||
static
|
static
|
||||||
bool create_repmgr_extension(PGconn *conn)
|
bool create_repmgr_extension(PGconn *conn)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,8 +37,9 @@
|
|||||||
#define CLUSTER_CLEANUP 14
|
#define CLUSTER_CLEANUP 14
|
||||||
#define CLUSTER_MATRIX 15
|
#define CLUSTER_MATRIX 15
|
||||||
#define CLUSTER_CROSSCHECK 16
|
#define CLUSTER_CROSSCHECK 16
|
||||||
#define BDR_REGISTER 17
|
#define CLUSTER_EVENT 17
|
||||||
#define BDR_UNREGISTER 18
|
#define BDR_REGISTER 18
|
||||||
|
#define BDR_UNREGISTER 19
|
||||||
|
|
||||||
/* command line options without short versions */
|
/* command line options without short versions */
|
||||||
#define OPT_HELP 1
|
#define OPT_HELP 1
|
||||||
@@ -72,6 +73,9 @@ static struct option long_options[] =
|
|||||||
|
|
||||||
/* connection options */
|
/* connection options */
|
||||||
{"superuser", required_argument, NULL, 'S'},
|
{"superuser", required_argument, NULL, 'S'},
|
||||||
|
{"pgdata", required_argument, NULL, 'D'},
|
||||||
|
/* legacy alias for -D/--pgdata*/
|
||||||
|
{"data-dir", required_argument, NULL, 'D'},
|
||||||
|
|
||||||
/* logging options */
|
/* logging options */
|
||||||
{"log-level", required_argument, NULL, 'L'},
|
{"log-level", required_argument, NULL, 'L'},
|
||||||
@@ -79,12 +83,11 @@ static struct option long_options[] =
|
|||||||
{"terse", required_argument, NULL, 't'},
|
{"terse", required_argument, NULL, 't'},
|
||||||
{"verbose", no_argument, NULL, 'v'},
|
{"verbose", no_argument, NULL, 'v'},
|
||||||
|
|
||||||
|
/* not yet handled */
|
||||||
{"dbname", required_argument, NULL, 'd'},
|
{"dbname", required_argument, NULL, 'd'},
|
||||||
{"host", required_argument, NULL, 'h'},
|
{"host", required_argument, NULL, 'h'},
|
||||||
{"port", required_argument, NULL, 'p'},
|
{"port", required_argument, NULL, 'p'},
|
||||||
{"username", required_argument, NULL, 'U'},
|
{"username", required_argument, NULL, 'U'},
|
||||||
{"superuser", required_argument, NULL, 'S'},
|
|
||||||
{"pgdata", required_argument, NULL, 'D'},
|
|
||||||
{"remote-user", required_argument, NULL, 'R'},
|
{"remote-user", required_argument, NULL, 'R'},
|
||||||
{"wal-keep-segments", required_argument, NULL, 'w'},
|
{"wal-keep-segments", required_argument, NULL, 'w'},
|
||||||
{"keep-history", required_argument, NULL, 'k'},
|
{"keep-history", required_argument, NULL, 'k'},
|
||||||
@@ -115,6 +118,11 @@ static struct option long_options[] =
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
/* configuration metadata */
|
||||||
|
bool conninfo_provided;
|
||||||
|
bool connection_param_provided;
|
||||||
|
bool host_param_provided;
|
||||||
|
|
||||||
/* general configuration options */
|
/* general configuration options */
|
||||||
char config_file[MAXPGPATH];
|
char config_file[MAXPGPATH];
|
||||||
bool force;
|
bool force;
|
||||||
@@ -127,25 +135,34 @@ typedef struct
|
|||||||
bool verbose;
|
bool verbose;
|
||||||
|
|
||||||
/* connection options */
|
/* connection options */
|
||||||
|
char data_dir[MAXPGPATH];
|
||||||
char superuser[MAXLEN];
|
char superuser[MAXLEN];
|
||||||
|
|
||||||
|
|
||||||
} t_runtime_options;
|
} t_runtime_options;
|
||||||
|
|
||||||
#define T_RUNTIME_OPTIONS_INITIALIZER { \
|
#define T_RUNTIME_OPTIONS_INITIALIZER { \
|
||||||
|
/* configuration metadata */ \
|
||||||
|
false, false, false, \
|
||||||
/* general configuration options */ \
|
/* general configuration options */ \
|
||||||
"", false, "", \
|
"", false, "", \
|
||||||
/* logging options */ \
|
/* logging options */ \
|
||||||
"", false, false, false, \
|
"", false, false, false, \
|
||||||
/* connection options */ \
|
/* connection options */ \
|
||||||
""}
|
"", ""}
|
||||||
|
|
||||||
static void do_help(void);
|
static void do_help(void);
|
||||||
static void do_master_register(void);
|
static void do_master_register(void);
|
||||||
|
|
||||||
static void do_standby_clone(void);
|
static void do_standby_clone(void);
|
||||||
|
|
||||||
|
static void do_cluster_event(void);
|
||||||
|
|
||||||
|
|
||||||
|
static const char *action_name(const int action);
|
||||||
static void exit_with_errors(void);
|
static void exit_with_errors(void);
|
||||||
static void print_error_list(ItemList *error_list, int log_level);
|
static void print_item_list(ItemList *item_list);
|
||||||
|
static void check_cli_parameters(const int action);
|
||||||
static int check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string);
|
static int check_server_version(PGconn *conn, char *server_type, bool exit_on_error, char *server_version_string);
|
||||||
static bool create_repmgr_extension(PGconn *conn);
|
static bool create_repmgr_extension(PGconn *conn);
|
||||||
|
|
||||||
|
|||||||
40
strutil.c
40
strutil.c
@@ -24,8 +24,8 @@ xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
|||||||
|
|
||||||
if (retval >= (int) size)
|
if (retval >= (int) size)
|
||||||
{
|
{
|
||||||
log_error(_("Buffer of size not large enough to format entire string '%s'"),
|
log_error(_("buffer of size not large enough to format entire string '%s'"),
|
||||||
str);
|
str);
|
||||||
exit(ERR_STR_OVERFLOW);
|
exit(ERR_STR_OVERFLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +60,42 @@ maxlen_snprintf(char *str, const char *format,...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
item_list_append(ItemList *item_list, const char *message)
|
||||||
|
{
|
||||||
|
item_list_append_format(item_list, "%s", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
item_list_append_format(ItemList *item_list, const char *format, ...)
|
||||||
|
{
|
||||||
|
ItemListCell *cell;
|
||||||
|
va_list arglist;
|
||||||
|
|
||||||
|
cell = (ItemListCell *) pg_malloc0(sizeof(ItemListCell));
|
||||||
|
|
||||||
|
if (cell == NULL)
|
||||||
|
{
|
||||||
|
log_error(_("unable to allocate memory; terminating."));
|
||||||
|
exit(ERR_BAD_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
cell->string = pg_malloc0(MAXLEN);
|
||||||
|
|
||||||
|
va_start(arglist, format);
|
||||||
|
|
||||||
|
(void) xvsnprintf(cell->string, MAXLEN, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
|
||||||
|
|
||||||
|
if (item_list->tail)
|
||||||
|
item_list->tail->next = cell;
|
||||||
|
else
|
||||||
|
item_list->head = cell;
|
||||||
|
|
||||||
|
item_list->tail = cell;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Escape a string for use as a parameter in recovery.conf
|
* Escape a string for use as a parameter in recovery.conf
|
||||||
* Caller must free returned value
|
* Caller must free returned value
|
||||||
|
|||||||
21
strutil.h
21
strutil.h
@@ -17,6 +17,19 @@
|
|||||||
|
|
||||||
#define MAXLEN_STR STR(MAXLEN)
|
#define MAXLEN_STR STR(MAXLEN)
|
||||||
|
|
||||||
|
typedef struct ItemListCell
|
||||||
|
{
|
||||||
|
struct ItemListCell *next;
|
||||||
|
char *string;
|
||||||
|
} ItemListCell;
|
||||||
|
|
||||||
|
typedef struct ItemList
|
||||||
|
{
|
||||||
|
ItemListCell *head;
|
||||||
|
ItemListCell *tail;
|
||||||
|
} ItemList;
|
||||||
|
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
sqlquery_snprintf(char *str, const char *format,...)
|
sqlquery_snprintf(char *str, const char *format,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
||||||
@@ -25,7 +38,15 @@ extern int
|
|||||||
maxlen_snprintf(char *str, const char *format,...)
|
maxlen_snprintf(char *str, const char *format,...)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
||||||
|
|
||||||
|
extern void
|
||||||
|
item_list_append(ItemList *item_list, const char *message);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
item_list_append_format(ItemList *item_list, const char *format, ...)
|
||||||
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
||||||
|
|
||||||
extern char *
|
extern char *
|
||||||
escape_recovery_conf_value(const char *src);
|
escape_recovery_conf_value(const char *src);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _STRUTIL_H_ */
|
#endif /* _STRUTIL_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user