mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-26 00:26:30 +00:00
sprintf to snprintf conversion
Move out string operations to another file, and introduce a frontend to snprintf for various situations. This change is important for catching and eliminating sprintf overflows, which are as of now many times silently corrupting memory. Signed-off-by: Dan Farina <drfarina@acm.org> Signed-off-by: Peter van Hardenberg <pvh@heroku.com>
This commit is contained in:
committed by
Peter van Hardenberg
parent
846c0b92e8
commit
916c0492fb
6
Makefile
6
Makefile
@@ -4,8 +4,10 @@
|
|||||||
# Copyright (c) 2ndQuadrant, 2010
|
# Copyright (c) 2ndQuadrant, 2010
|
||||||
# Copyright (c) Heroku, 2010
|
# Copyright (c) Heroku, 2010
|
||||||
|
|
||||||
repmgrd_OBJS = dbutils.o config.o repmgrd.o
|
repmgrd_OBJS = dbutils.o config.o repmgrd.o strutil.o
|
||||||
repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o
|
repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o strutil.o
|
||||||
|
|
||||||
|
DATA = repmgr.sql uninstall_repmgr.sql
|
||||||
|
|
||||||
PG_CPPFLAGS = -I$(libpq_srcdir)
|
PG_CPPFLAGS = -I$(libpq_srcdir)
|
||||||
PG_LIBS = $(libpq_pgport)
|
PG_LIBS = $(libpq_pgport)
|
||||||
|
|||||||
12
check_dir.c
12
check_dir.c
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* check_dir.c
|
* check_dir.c
|
||||||
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (c) 2ndQuadrant, 2010
|
||||||
|
* Copyright (c) Heroku, 2010
|
||||||
*
|
*
|
||||||
* Directories management functions
|
* Directories management functions
|
||||||
*/
|
*/
|
||||||
@@ -12,9 +14,12 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/* NB: postgres_fe must be included BEFORE check_dir */
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
#include "check_dir.h"
|
#include "check_dir.h"
|
||||||
|
|
||||||
|
#include "strutil.h"
|
||||||
|
|
||||||
|
|
||||||
static int mkdir_p(char *path, mode_t omode);
|
static int mkdir_p(char *path, mode_t omode);
|
||||||
|
|
||||||
@@ -207,10 +212,11 @@ mkdir_p(char *path, mode_t omode)
|
|||||||
bool
|
bool
|
||||||
is_pg_dir(char *dir)
|
is_pg_dir(char *dir)
|
||||||
{
|
{
|
||||||
char path[8192];
|
const size_t buf_sz = 8192;
|
||||||
struct stat sb;
|
char path[buf_sz];
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
sprintf(path, "%s/PG_VERSION", dir);
|
xsnprintf(path, buf_sz, "%s/PG_VERSION", dir);
|
||||||
|
|
||||||
return (stat(path, &sb) == 0) ? true : false;
|
return (stat(path, &sb) == 0) ? true : false;
|
||||||
}
|
}
|
||||||
|
|||||||
4
config.c
4
config.c
@@ -1,12 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* config.c
|
* config.c
|
||||||
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (c) 2ndQuadrant, 2010
|
||||||
|
* Copyright (c) Heroku, 2010
|
||||||
*
|
*
|
||||||
* Functions to parse the config file
|
* Functions to parse the config file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "repmgr.h"
|
#include "repmgr.h"
|
||||||
|
|
||||||
|
#include "strutil.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
parse_config(const char *config_file, char *cluster_name, int *node,
|
parse_config(const char *config_file, char *cluster_name, int *node,
|
||||||
char *conninfo)
|
char *conninfo)
|
||||||
|
|||||||
28
dbutils.c
28
dbutils.c
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "repmgr.h"
|
#include "repmgr.h"
|
||||||
|
#include "strutil.h"
|
||||||
|
|
||||||
PGconn *
|
PGconn *
|
||||||
establishDBConnection(const char *conninfo, const bool exit_on_error)
|
establishDBConnection(const char *conninfo, const bool exit_on_error)
|
||||||
@@ -66,11 +67,13 @@ is_standby(PGconn *conn)
|
|||||||
char *
|
char *
|
||||||
pg_version(PGconn *conn)
|
pg_version(PGconn *conn)
|
||||||
{
|
{
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
char *major_version;
|
|
||||||
|
|
||||||
int major_version1;
|
const size_t major_version_sz = 10;
|
||||||
char *major_version2;
|
char *major_version;
|
||||||
|
|
||||||
|
int major_version1;
|
||||||
|
char *major_version2;
|
||||||
|
|
||||||
res = PQexec(conn,
|
res = PQexec(conn,
|
||||||
"WITH pg_version(ver) AS "
|
"WITH pg_version(ver) AS "
|
||||||
@@ -90,12 +93,13 @@ pg_version(PGconn *conn)
|
|||||||
major_version2 = PQgetvalue(res, 0, 1);
|
major_version2 = PQgetvalue(res, 0, 1);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
major_version = malloc(10);
|
major_version = malloc(major_version_sz);
|
||||||
|
|
||||||
if (major_version1 >= 9)
|
if (major_version1 >= 9)
|
||||||
{
|
{
|
||||||
/* form a major version string */
|
/* form a major version string */
|
||||||
sprintf(major_version, "%d.%s", major_version1, major_version2);
|
xsnprintf(major_version, major_version_sz, "%d.%s",
|
||||||
|
major_version1, major_version2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
strcpy(major_version, "");
|
strcpy(major_version, "");
|
||||||
@@ -109,9 +113,9 @@ guc_setted(PGconn *conn, const char *parameter, const char *op,
|
|||||||
const char *value)
|
const char *value)
|
||||||
{
|
{
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
char sqlquery[8192];
|
char sqlquery[QUERY_STR_LEN];
|
||||||
|
|
||||||
sprintf(sqlquery, "SELECT true FROM pg_settings "
|
sqlquery_snprintf(sqlquery, "SELECT true FROM pg_settings "
|
||||||
" WHERE name = '%s' AND setting %s '%s'",
|
" WHERE name = '%s' AND setting %s '%s'",
|
||||||
parameter, op, value);
|
parameter, op, value);
|
||||||
|
|
||||||
@@ -139,9 +143,9 @@ get_cluster_size(PGconn *conn)
|
|||||||
{
|
{
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
const char *size;
|
const char *size;
|
||||||
char sqlquery[8192];
|
char sqlquery[QUERY_STR_LEN];
|
||||||
|
|
||||||
sprintf(sqlquery,
|
sqlquery_snprintf(sqlquery,
|
||||||
"SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) "
|
"SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) "
|
||||||
" FROM pg_database ");
|
" FROM pg_database ");
|
||||||
|
|
||||||
@@ -169,12 +173,12 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster,
|
|||||||
PGconn *master_conn = NULL;
|
PGconn *master_conn = NULL;
|
||||||
PGresult *res1;
|
PGresult *res1;
|
||||||
PGresult *res2;
|
PGresult *res2;
|
||||||
char sqlquery[8192];
|
char sqlquery[QUERY_STR_LEN];
|
||||||
char master_conninfo[8192];
|
char master_conninfo[8192];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* find all nodes belonging to this cluster */
|
/* find all nodes belonging to this cluster */
|
||||||
sprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
|
||||||
" WHERE cluster = '%s' and id <> %d",
|
" WHERE cluster = '%s' and id <> %d",
|
||||||
cluster, cluster, id);
|
cluster, cluster, id);
|
||||||
|
|
||||||
|
|||||||
90
repmgr.c
90
repmgr.c
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* repmgr.c
|
* repmgr.c
|
||||||
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (c) 2ndQuadrant, 2010
|
||||||
|
* Copyright (c) Heroku, 2010
|
||||||
*
|
*
|
||||||
* Command interpreter for the repmgr
|
* Command interpreter for the repmgr
|
||||||
* This module is a command-line utility to easily setup a cluster of
|
* This module is a command-line utility to easily setup a cluster of
|
||||||
@@ -19,6 +21,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "check_dir.h"
|
#include "check_dir.h"
|
||||||
|
#include "strutil.h"
|
||||||
|
|
||||||
#define RECOVERY_FILE "recovery.conf"
|
#define RECOVERY_FILE "recovery.conf"
|
||||||
#define RECOVERY_DONE_FILE "recovery.done"
|
#define RECOVERY_DONE_FILE "recovery.done"
|
||||||
@@ -30,7 +33,6 @@
|
|||||||
#define STANDBY_PROMOTE 4
|
#define STANDBY_PROMOTE 4
|
||||||
#define STANDBY_FOLLOW 5
|
#define STANDBY_FOLLOW 5
|
||||||
|
|
||||||
#define QUERY_STR_LEN 8192
|
|
||||||
|
|
||||||
static void help(const char *progname);
|
static void help(const char *progname);
|
||||||
static bool create_recovery_file(const char *data_dir);
|
static bool create_recovery_file(const char *data_dir);
|
||||||
@@ -227,8 +229,10 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
if (config_file == NULL)
|
if (config_file == NULL)
|
||||||
{
|
{
|
||||||
config_file = malloc(5 + sizeof(CONFIG_FILE));
|
const int buf_sz = 3 + sizeof(CONFIG_FILE);
|
||||||
sprintf(config_file, "./%s", CONFIG_FILE);
|
|
||||||
|
config_file = malloc(buf_sz);
|
||||||
|
xsnprintf(config_file, buf_sz, "./%s", CONFIG_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wal_keep_segments == NULL)
|
if (wal_keep_segments == NULL)
|
||||||
@@ -329,7 +333,8 @@ do_master_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check if there is a schema for this cluster */
|
/* Check if there is a schema for this cluster */
|
||||||
sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'",
|
sqlquery_snprintf(sqlquery,
|
||||||
|
"SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'",
|
||||||
myClusterName);
|
myClusterName);
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
@@ -357,7 +362,7 @@ do_master_register(void)
|
|||||||
if (!schema_exists)
|
if (!schema_exists)
|
||||||
{
|
{
|
||||||
/* ok, create the schema */
|
/* ok, create the schema */
|
||||||
sprintf(sqlquery, "CREATE SCHEMA repmgr_%s", myClusterName);
|
sqlquery_snprintf(sqlquery, "CREATE SCHEMA repmgr_%s", myClusterName);
|
||||||
if (!PQexec(conn, sqlquery))
|
if (!PQexec(conn, sqlquery))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Cannot create the schema repmgr_%s: %s\n",
|
fprintf(stderr, "Cannot create the schema repmgr_%s: %s\n",
|
||||||
@@ -367,7 +372,7 @@ do_master_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ... the tables */
|
/* ... the tables */
|
||||||
sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( "
|
sqlquery_snprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( "
|
||||||
" id integer primary key, "
|
" id integer primary key, "
|
||||||
" cluster text not null, "
|
" cluster text not null, "
|
||||||
" conninfo text not null)", myClusterName);
|
" conninfo text not null)", myClusterName);
|
||||||
@@ -380,7 +385,7 @@ do_master_register(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_monitor ( "
|
sqlquery_snprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_monitor ( "
|
||||||
" primary_node INTEGER NOT NULL, "
|
" primary_node INTEGER NOT NULL, "
|
||||||
" standby_node INTEGER NOT NULL, "
|
" standby_node INTEGER NOT NULL, "
|
||||||
" last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, "
|
" last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, "
|
||||||
@@ -399,7 +404,7 @@ do_master_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* and the view */
|
/* and the view */
|
||||||
sprintf(sqlquery, "CREATE VIEW repmgr_%s.repl_status AS "
|
sqlquery_snprintf(sqlquery, "CREATE VIEW repmgr_%s.repl_status AS "
|
||||||
" WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node "
|
" WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node "
|
||||||
" ORDER BY last_monitor_time desc) "
|
" ORDER BY last_monitor_time desc) "
|
||||||
" FROM repmgr_%s.repl_monitor) "
|
" FROM repmgr_%s.repl_monitor) "
|
||||||
@@ -435,7 +440,7 @@ do_master_register(void)
|
|||||||
/* Now register the master */
|
/* Now register the master */
|
||||||
if (force)
|
if (force)
|
||||||
{
|
{
|
||||||
sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes "
|
||||||
" WHERE id = %d",
|
" WHERE id = %d",
|
||||||
myClusterName, myLocalId);
|
myClusterName, myLocalId);
|
||||||
|
|
||||||
@@ -448,7 +453,7 @@ do_master_register(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
||||||
"VALUES (%d, '%s', '%s')",
|
"VALUES (%d, '%s', '%s')",
|
||||||
myClusterName, myLocalId, myClusterName, conninfo);
|
myClusterName, myLocalId, myClusterName, conninfo);
|
||||||
|
|
||||||
@@ -514,7 +519,7 @@ do_standby_register(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check if there is a schema for this cluster */
|
/* Check if there is a schema for this cluster */
|
||||||
sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'",
|
sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'",
|
||||||
myClusterName);
|
myClusterName);
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
@@ -566,7 +571,7 @@ do_standby_register(void)
|
|||||||
/* Now register the standby */
|
/* Now register the standby */
|
||||||
if (force)
|
if (force)
|
||||||
{
|
{
|
||||||
sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes "
|
||||||
" WHERE id = %d",
|
" WHERE id = %d",
|
||||||
myClusterName, myLocalId);
|
myClusterName, myLocalId);
|
||||||
|
|
||||||
@@ -580,7 +585,7 @@ do_standby_register(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
||||||
"VALUES (%d, '%s', '%s')",
|
"VALUES (%d, '%s', '%s')",
|
||||||
myClusterName, myLocalId, myClusterName, conninfo);
|
myClusterName, myLocalId, myClusterName, conninfo);
|
||||||
|
|
||||||
@@ -744,7 +749,7 @@ do_standby_clone(void)
|
|||||||
printf(_("Succesfully connected to primary. Current installation size is %s\n"), get_cluster_size(conn));
|
printf(_("Succesfully connected to primary. Current installation size is %s\n"), get_cluster_size(conn));
|
||||||
|
|
||||||
/* Check if the tablespace locations exists and that we can write to them */
|
/* Check if the tablespace locations exists and that we can write to them */
|
||||||
sprintf(sqlquery, "select spclocation from pg_tablespace where spcname not in ('pg_default', 'pg_global')");
|
sqlquery_snprintf(sqlquery, "select spclocation from pg_tablespace where spcname not in ('pg_default', 'pg_global')");
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
@@ -819,7 +824,7 @@ do_standby_clone(void)
|
|||||||
fprintf(stderr, "Starting backup...\n");
|
fprintf(stderr, "Starting backup...\n");
|
||||||
|
|
||||||
/* Get the data directory full path and the configuration files location */
|
/* Get the data directory full path and the configuration files location */
|
||||||
sprintf(sqlquery, "SELECT name, setting "
|
sqlquery_snprintf(sqlquery, "SELECT name, setting "
|
||||||
" FROM pg_settings "
|
" FROM pg_settings "
|
||||||
" WHERE name IN ('data_directory', 'config_file', 'hba_file', 'ident_file')");
|
" WHERE name IN ('data_directory', 'config_file', 'hba_file', 'ident_file')");
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
@@ -849,7 +854,7 @@ do_standby_clone(void)
|
|||||||
* inform the master we will start a backup and get the first XLog filename
|
* inform the master we will start a backup and get the first XLog filename
|
||||||
* so we can say to the user we need those files
|
* so we can say to the user we need those files
|
||||||
*/
|
*/
|
||||||
sprintf(sqlquery, "SELECT pg_xlogfile_name(pg_start_backup('repmgr_standby_clone_%ld'))", time(NULL));
|
sqlquery_snprintf(sqlquery, "SELECT pg_xlogfile_name(pg_start_backup('repmgr_standby_clone_%ld'))", time(NULL));
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
@@ -876,9 +881,9 @@ do_standby_clone(void)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* need to create the global sub directory */
|
/* need to create the global sub directory */
|
||||||
sprintf(master_control_file, "%s/global/pg_control",
|
maxlen_snprintf(master_control_file, "%s/global/pg_control",
|
||||||
master_data_directory);
|
master_data_directory);
|
||||||
sprintf(local_control_file, "%s/global", dest_dir);
|
maxlen_snprintf(local_control_file, "%s/global", dest_dir);
|
||||||
if (!create_directory(local_control_file))
|
if (!create_directory(local_control_file))
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: couldn't create directory %s ... "),
|
fprintf(stderr, _("%s: couldn't create directory %s ... "),
|
||||||
@@ -901,7 +906,7 @@ do_standby_clone(void)
|
|||||||
* find and appropiate rsync option but besides we could someday make all
|
* find and appropiate rsync option but besides we could someday make all
|
||||||
* these rsync happen concurrently
|
* these rsync happen concurrently
|
||||||
*/
|
*/
|
||||||
sprintf(sqlquery, "select spclocation from pg_tablespace where spcname not in ('pg_default', 'pg_global')");
|
sqlquery_snprintf(sqlquery, "select spclocation from pg_tablespace where spcname not in ('pg_default', 'pg_global')");
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
@@ -944,7 +949,7 @@ stop_backup:
|
|||||||
|
|
||||||
fprintf(stderr, "Finishing backup...\n");
|
fprintf(stderr, "Finishing backup...\n");
|
||||||
|
|
||||||
sprintf(sqlquery, "SELECT pg_xlogfile_name(pg_stop_backup())");
|
sqlquery_snprintf(sqlquery, "SELECT pg_xlogfile_name(pg_stop_backup())");
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
{
|
{
|
||||||
@@ -970,7 +975,7 @@ stop_backup:
|
|||||||
* We need to create the pg_xlog sub directory too, I'm reusing a variable
|
* We need to create the pg_xlog sub directory too, I'm reusing a variable
|
||||||
* here.
|
* here.
|
||||||
*/
|
*/
|
||||||
sprintf(local_control_file, "%s/pg_xlog", dest_dir);
|
maxlen_snprintf(local_control_file, "%s/pg_xlog", dest_dir);
|
||||||
if (!create_directory(local_control_file))
|
if (!create_directory(local_control_file))
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: couldn't create directory %s, you will need to do it manually...\n"),
|
fprintf(stderr, _("%s: couldn't create directory %s, you will need to do it manually...\n"),
|
||||||
@@ -994,7 +999,7 @@ do_standby_promote(void)
|
|||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
char sqlquery[QUERY_STR_LEN];
|
char sqlquery[QUERY_STR_LEN];
|
||||||
char script[QUERY_STR_LEN];
|
char script[MAXLEN];
|
||||||
|
|
||||||
char myClusterName[MAXLEN];
|
char myClusterName[MAXLEN];
|
||||||
int myLocalId = -1;
|
int myLocalId = -1;
|
||||||
@@ -1056,7 +1061,7 @@ do_standby_promote(void)
|
|||||||
printf(_("\n%s: Promoting standby...\n"), progname);
|
printf(_("\n%s: Promoting standby...\n"), progname);
|
||||||
|
|
||||||
/* Get the data directory full path and the last subdirectory */
|
/* Get the data directory full path and the last subdirectory */
|
||||||
sprintf(sqlquery, "SELECT setting "
|
sqlquery_snprintf(sqlquery, "SELECT setting "
|
||||||
" FROM pg_settings WHERE name = 'data_directory'");
|
" FROM pg_settings WHERE name = 'data_directory'");
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
@@ -1071,12 +1076,12 @@ do_standby_promote(void)
|
|||||||
PQclear(res);
|
PQclear(res);
|
||||||
PQfinish(conn);
|
PQfinish(conn);
|
||||||
|
|
||||||
sprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE);
|
maxlen_snprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE);
|
||||||
sprintf(recovery_done_path, "%s/%s", data_dir, RECOVERY_DONE_FILE);
|
maxlen_snprintf(recovery_done_path, "%s/%s", data_dir, RECOVERY_DONE_FILE);
|
||||||
rename(recovery_file_path, recovery_done_path);
|
rename(recovery_file_path, recovery_done_path);
|
||||||
|
|
||||||
/* We assume the pg_ctl script is in the PATH */
|
/* We assume the pg_ctl script is in the PATH */
|
||||||
sprintf(script, "pg_ctl -D %s -m fast restart", data_dir);
|
maxlen_snprintf(script, "pg_ctl -D %s -m fast restart", data_dir);
|
||||||
r = system(script);
|
r = system(script);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
{
|
{
|
||||||
@@ -1108,7 +1113,7 @@ do_standby_follow(void)
|
|||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
char sqlquery[QUERY_STR_LEN];
|
char sqlquery[QUERY_STR_LEN];
|
||||||
char script[QUERY_STR_LEN];
|
char script[MAXLEN];
|
||||||
|
|
||||||
char myClusterName[MAXLEN];
|
char myClusterName[MAXLEN];
|
||||||
int myLocalId = -1;
|
int myLocalId = -1;
|
||||||
@@ -1206,7 +1211,7 @@ do_standby_follow(void)
|
|||||||
printf(_("\n%s: Changing standby's master...\n"), progname);
|
printf(_("\n%s: Changing standby's master...\n"), progname);
|
||||||
|
|
||||||
/* Get the data directory full path */
|
/* Get the data directory full path */
|
||||||
sprintf(sqlquery, "SELECT setting "
|
sqlquery_snprintf(sqlquery, "SELECT setting "
|
||||||
" FROM pg_settings WHERE name = 'data_directory'");
|
" FROM pg_settings WHERE name = 'data_directory'");
|
||||||
res = PQexec(conn, sqlquery);
|
res = PQexec(conn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
@@ -1227,7 +1232,7 @@ do_standby_follow(void)
|
|||||||
|
|
||||||
/* Finally, restart the service */
|
/* Finally, restart the service */
|
||||||
/* We assume the pg_ctl script is in the PATH */
|
/* We assume the pg_ctl script is in the PATH */
|
||||||
sprintf(script, "pg_ctl -D %s -m fast restart", data_dir);
|
maxlen_snprintf(script, "pg_ctl -D %s -m fast restart", data_dir);
|
||||||
r = system(script);
|
r = system(script);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
{
|
{
|
||||||
@@ -1282,7 +1287,7 @@ create_recovery_file(const char *data_dir)
|
|||||||
char recovery_file_path[MAXLEN];
|
char recovery_file_path[MAXLEN];
|
||||||
char line[MAXLEN];
|
char line[MAXLEN];
|
||||||
|
|
||||||
sprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE);
|
maxlen_snprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE);
|
||||||
|
|
||||||
recovery_file = fopen(recovery_file_path, "w");
|
recovery_file = fopen(recovery_file_path, "w");
|
||||||
if (recovery_file == NULL)
|
if (recovery_file == NULL)
|
||||||
@@ -1291,7 +1296,7 @@ create_recovery_file(const char *data_dir)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(line, "standby_mode = 'on'\n");
|
maxlen_snprintf(line, "standby_mode = 'on'\n");
|
||||||
if (fputs(line, recovery_file) == EOF)
|
if (fputs(line, recovery_file) == EOF)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n");
|
fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n");
|
||||||
@@ -1299,7 +1304,7 @@ create_recovery_file(const char *data_dir)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(line, "primary_conninfo = 'host=%s port=%s'\n", host,
|
maxlen_snprintf(line, "primary_conninfo = 'host=%s port=%s'\n", host,
|
||||||
((masterport==NULL) ? "5432" : masterport));
|
((masterport==NULL) ? "5432" : masterport));
|
||||||
if (fputs(line, recovery_file) == EOF)
|
if (fputs(line, recovery_file) == EOF)
|
||||||
{
|
{
|
||||||
@@ -1319,35 +1324,36 @@ static int
|
|||||||
copy_remote_files(char *host, char *remote_user, char *remote_path,
|
copy_remote_files(char *host, char *remote_user, char *remote_path,
|
||||||
char *local_path, bool is_directory)
|
char *local_path, bool is_directory)
|
||||||
{
|
{
|
||||||
char script[QUERY_STR_LEN];
|
char script[MAXLEN];
|
||||||
char options[QUERY_STR_LEN];
|
char options[MAXLEN];
|
||||||
char host_string[QUERY_STR_LEN];
|
char host_string[MAXLEN];
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
sprintf(options, "--archive --checksum --compress --progress --rsh=ssh");
|
maxlen_snprintf(options,
|
||||||
|
"--archive --checksum --compress --progress --rsh=ssh");
|
||||||
if (force)
|
if (force)
|
||||||
strcat(options, " --delete");
|
strcat(options, " --delete");
|
||||||
|
|
||||||
if (remote_user == NULL)
|
if (remote_user == NULL)
|
||||||
{
|
{
|
||||||
sprintf(host_string,"%s",host);
|
maxlen_snprintf(host_string, "%s", host);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(host_string,"%s@%s",remote_user,host);
|
maxlen_snprintf(host_string,"%s@%s",remote_user,host);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_directory)
|
if (is_directory)
|
||||||
{
|
{
|
||||||
strcat(options,
|
strcat(options,
|
||||||
" --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid");
|
" --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid");
|
||||||
sprintf(script, "rsync %s %s:%s/* %s",
|
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
|
||||||
options, host_string, remote_path, local_path);
|
options, host_string, remote_path, local_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(script, "rsync %s %s:%s %s/.",
|
maxlen_snprintf(script, "rsync %s %s:%s %s/.",
|
||||||
options, host_string, remote_path, local_path);
|
options, host_string, remote_path, local_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
|||||||
5
repmgr.h
5
repmgr.h
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* dbutils.h
|
* repmgr.h
|
||||||
|
*
|
||||||
* Copyright (c) 2ndQuadrant, 2010
|
* Copyright (c) 2ndQuadrant, 2010
|
||||||
|
* Copyright (c) Heroku, 2010
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -18,7 +20,6 @@
|
|||||||
#define PRIMARY_MODE 0
|
#define PRIMARY_MODE 0
|
||||||
#define STANDBY_MODE 1
|
#define STANDBY_MODE 1
|
||||||
|
|
||||||
#define MAXLEN 80
|
|
||||||
#define CONFIG_FILE "repmgr.conf"
|
#define CONFIG_FILE "repmgr.conf"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
21
repmgrd.c
21
repmgrd.c
@@ -14,6 +14,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "repmgr.h"
|
#include "repmgr.h"
|
||||||
|
#include "strutil.h"
|
||||||
|
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ int primaryId;
|
|||||||
char primaryConninfo[MAXLEN];
|
char primaryConninfo[MAXLEN];
|
||||||
PGconn *primaryConn;
|
PGconn *primaryConn;
|
||||||
|
|
||||||
char sqlquery[8192];
|
char sqlquery[QUERY_STR_LEN];
|
||||||
|
|
||||||
const char *progname;
|
const char *progname;
|
||||||
|
|
||||||
@@ -121,8 +122,10 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
if (config_file == NULL)
|
if (config_file == NULL)
|
||||||
{
|
{
|
||||||
config_file = malloc(5 + sizeof(CONFIG_FILE));
|
const size_t buf_sz = 3 + sizeof(CONFIG_FILE);
|
||||||
sprintf(config_file, "./%s", CONFIG_FILE);
|
|
||||||
|
config_file = malloc(buf_sz);
|
||||||
|
xsnprintf(config_file, buf_sz, "./%s", CONFIG_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -270,7 +273,7 @@ MonitorExecute(void)
|
|||||||
CancelQuery();
|
CancelQuery();
|
||||||
|
|
||||||
/* Get local xlog info */
|
/* Get local xlog info */
|
||||||
sprintf(sqlquery,
|
sqlquery_snprintf(sqlquery,
|
||||||
"SELECT CURRENT_TIMESTAMP, pg_last_xlog_receive_location(), "
|
"SELECT CURRENT_TIMESTAMP, pg_last_xlog_receive_location(), "
|
||||||
"pg_last_xlog_replay_location()");
|
"pg_last_xlog_replay_location()");
|
||||||
|
|
||||||
@@ -289,7 +292,7 @@ MonitorExecute(void)
|
|||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
/* Get primary xlog info */
|
/* Get primary xlog info */
|
||||||
sprintf(sqlquery, "SELECT pg_current_xlog_location() ");
|
sqlquery_snprintf(sqlquery, "SELECT pg_current_xlog_location() ");
|
||||||
|
|
||||||
res = PQexec(primaryConn, sqlquery);
|
res = PQexec(primaryConn, sqlquery);
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
@@ -310,7 +313,7 @@ MonitorExecute(void)
|
|||||||
/*
|
/*
|
||||||
* Build the SQL to execute on primary
|
* Build the SQL to execute on primary
|
||||||
*/
|
*/
|
||||||
sprintf(sqlquery,
|
sqlquery_snprintf(sqlquery,
|
||||||
"INSERT INTO repmgr_%s.repl_monitor "
|
"INSERT INTO repmgr_%s.repl_monitor "
|
||||||
"VALUES(%d, %d, '%s'::timestamp with time zone, "
|
"VALUES(%d, %d, '%s'::timestamp with time zone, "
|
||||||
" '%s', '%s', "
|
" '%s', '%s', "
|
||||||
@@ -336,7 +339,7 @@ checkClusterConfiguration(void)
|
|||||||
{
|
{
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
|
|
||||||
sprintf(sqlquery, "SELECT oid FROM pg_class "
|
sqlquery_snprintf(sqlquery, "SELECT oid FROM pg_class "
|
||||||
" WHERE oid = 'repmgr_%s.repl_nodes'::regclass",
|
" WHERE oid = 'repmgr_%s.repl_nodes'::regclass",
|
||||||
myClusterName);
|
myClusterName);
|
||||||
res = PQexec(myLocalConn, sqlquery);
|
res = PQexec(myLocalConn, sqlquery);
|
||||||
@@ -374,7 +377,7 @@ checkNodeConfiguration(char *conninfo)
|
|||||||
PGresult *res;
|
PGresult *res;
|
||||||
|
|
||||||
/* Check if we have my node information in repl_nodes */
|
/* Check if we have my node information in repl_nodes */
|
||||||
sprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes "
|
||||||
" WHERE id = %d AND cluster = '%s' ",
|
" WHERE id = %d AND cluster = '%s' ",
|
||||||
myClusterName, myLocalId, myClusterName);
|
myClusterName, myLocalId, myClusterName);
|
||||||
|
|
||||||
@@ -397,7 +400,7 @@ checkNodeConfiguration(char *conninfo)
|
|||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
/* Adding the node */
|
/* Adding the node */
|
||||||
sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes "
|
||||||
"VALUES (%d, '%s', '%s')",
|
"VALUES (%d, '%s', '%s')",
|
||||||
myClusterName, myLocalId, myClusterName, conninfo);
|
myClusterName, myLocalId, myClusterName, conninfo);
|
||||||
|
|
||||||
|
|||||||
72
strutil.c
Normal file
72
strutil.c
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* strutil.c
|
||||||
|
*
|
||||||
|
* Copyright (c) Heroku, 2010
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "strutil.h"
|
||||||
|
|
||||||
|
static int xvsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
xvsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = vsnprintf(str, size, format, ap);
|
||||||
|
|
||||||
|
if (retval >= size)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Buffer not large enough to format entire string\n");
|
||||||
|
exit(255);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
xsnprintf(char *str, size_t size, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list arglist;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
va_start(arglist, format);
|
||||||
|
retval = xvsnprintf(str, size, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
sqlquery_snprintf(char *str, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list arglist;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
va_start(arglist, format);
|
||||||
|
retval = xvsnprintf(str, QUERY_STR_LEN, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int maxlen_snprintf(char *str, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list arglist;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
va_start(arglist, format);
|
||||||
|
retval = xvsnprintf(str, MAXLEN, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
19
strutil.h
Normal file
19
strutil.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* strutil.h
|
||||||
|
*
|
||||||
|
* Copyright (c) Heroku, 2010
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STRUTIL_H_
|
||||||
|
#define _STRUTIL_H_
|
||||||
|
|
||||||
|
#define QUERY_STR_LEN 8192
|
||||||
|
#define MAXLEN 80
|
||||||
|
|
||||||
|
|
||||||
|
extern int xsnprintf(char *str, size_t size, const char *format, ...);
|
||||||
|
extern int sqlquery_snprintf(char *str, const char *format, ...);
|
||||||
|
extern int maxlen_snprintf(char *str, const char *format, ...);
|
||||||
|
|
||||||
|
#endif /* _STRUTIL_H_ */
|
||||||
Reference in New Issue
Block a user