From af2edf10a0fe8e75c9378bdaf55c9b86760069b2 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Sun, 5 Dec 2010 23:31:22 -0800 Subject: [PATCH 01/34] Attack of whitespace pedantry pgsql conventions (tabs, four-spaces-wide, etc) applied all around. Also tried to fix some very tiny capitalization errors, auto-fill problems, and some inter-block vertical whitespacing issues. Long strings in repmgr.c were left intact, though. They are rather numerous and are less of a problem than tiny bits of function calls and comments wrapping over a line; the latter kind of problem has been mostly fixed. Signed-off-by: Dan Farina Signed-off-by: Peter van Hardenberg --- check_dir.c | 80 ++-- config.c | 66 +-- config.h | 3 +- dbutils.c | 172 ++++---- dbutils.h | 10 +- repmgr.c | 1140 +++++++++++++++++++++++++++------------------------ repmgr.sql | 26 +- repmgrd.c | 295 ++++++------- 8 files changed, 941 insertions(+), 851 deletions(-) diff --git a/check_dir.c b/check_dir.c index d63d7c2a..7296261d 100644 --- a/check_dir.c +++ b/check_dir.c @@ -31,63 +31,63 @@ static int mkdir_p(char *path, mode_t omode); int check_dir(char *dir) { - DIR *chkdir; - struct dirent *file; - int result = 1; + DIR *chkdir; + struct dirent *file; + int result = 1; - errno = 0; + errno = 0; - chkdir = opendir(dir); + chkdir = opendir(dir); - if (!chkdir) - return (errno == ENOENT) ? 0 : -1; + if (!chkdir) + return (errno == ENOENT) ? 0 : -1; - while ((file = readdir(chkdir)) != NULL) - { - if (strcmp(".", file->d_name) == 0 || - strcmp("..", file->d_name) == 0) - { - /* skip this and parent directory */ - continue; - } - else - { - result = 2; /* not empty */ - break; - } - } + while ((file = readdir(chkdir)) != NULL) + { + if (strcmp(".", file->d_name) == 0 || + strcmp("..", file->d_name) == 0) + { + /* skip this and parent directory */ + continue; + } + else + { + result = 2; /* not empty */ + break; + } + } #ifdef WIN32 - /* - * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in - * released version - */ - if (GetLastError() == ERROR_NO_MORE_FILES) - errno = 0; + /* + * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in + * released version + */ + if (GetLastError() == ERROR_NO_MORE_FILES) + errno = 0; #endif - closedir(chkdir); + closedir(chkdir); - if (errno != 0) - return -1; /* some kind of I/O error? */ + if (errno != 0) + return -1; /* some kind of I/O error? */ return result; } /* - * Create directory + * Create directory */ bool create_directory(char *dir) { - if (mkdir_p(dir, 0700) == 0) - return true; + if (mkdir_p(dir, 0700) == 0) + return true; - fprintf(stderr, _("Could not create directory \"%s\": %s\n"), - dir, strerror(errno)); + fprintf(stderr, _("Could not create directory \"%s\": %s\n"), + dir, strerror(errno)); - return false; + return false; } bool @@ -114,10 +114,10 @@ mkdir_p(char *path, mode_t omode) { struct stat sb; mode_t numask, - oumask; + oumask; int first, - last, - retval; + last, + retval; char *p; p = path; @@ -212,5 +212,5 @@ is_pg_dir(char *dir) sprintf(path, "%s/PG_VERSION", dir); - return (stat(path, &sb) == 0) ? true : false; + return (stat(path, &sb) == 0) ? true : false; } diff --git a/config.c b/config.c index 4d15f0b3..4c4ecdb6 100644 --- a/config.c +++ b/config.c @@ -8,13 +8,14 @@ #include "repmgr.h" void -parse_config(const char *config_file, char *cluster_name, int *node, char *conninfo) +parse_config(const char *config_file, char *cluster_name, int *node, + char *conninfo) { char *s, buff[256]; FILE *fp = fopen (config_file, "r"); if (fp == NULL) - return; + return; /* Read next line */ while ((s = fgets (buff, sizeof buff, fp)) != NULL) @@ -22,46 +23,47 @@ parse_config(const char *config_file, char *cluster_name, int *node, char *conni char name[MAXLEN]; char value[MAXLEN]; - /* Skip blank lines and comments */ - if (buff[0] == '\n' || buff[0] == '#') - continue; + /* Skip blank lines and comments */ + if (buff[0] == '\n' || buff[0] == '#') + continue; - /* Parse name/value pair from line */ + /* Parse name/value pair from line */ parse_line(buff, name, value); - /* Copy into correct entry in parameters struct */ - if (strcmp(name, "cluster") == 0) - strncpy (cluster_name, value, MAXLEN); - else if (strcmp(name, "node") == 0) - *node = atoi(value); - else if (strcmp(name, "conninfo") == 0) - strncpy (conninfo, value, MAXLEN); - else - printf ("WARNING: %s/%s: Unknown name/value pair!\n", name, value); - } + /* Copy into correct entry in parameters struct */ + if (strcmp(name, "cluster") == 0) + strncpy (cluster_name, value, MAXLEN); + else if (strcmp(name, "node") == 0) + *node = atoi(value); + else if (strcmp(name, "conninfo") == 0) + strncpy (conninfo, value, MAXLEN); + else + printf("WARNING: %s/%s: Unknown name/value pair!\n", + name, value); + } - /* Close file */ - fclose (fp); + /* Close file */ + fclose (fp); } char * trim (char *s) { - /* Initialize start, end pointers */ - char *s1 = s, *s2 = &s[strlen (s) - 1]; + /* Initialize start, end pointers */ + char *s1 = s, *s2 = &s[strlen (s) - 1]; - /* Trim and delimit right side */ - while ( (isspace (*s2)) && (s2 >= s1) ) - s2--; - *(s2+1) = '\0'; + /* Trim and delimit right side */ + while ( (isspace (*s2)) && (s2 >= s1) ) + s2--; + *(s2+1) = '\0'; - /* Trim left side */ - while ( (isspace (*s1)) && (s1 < s2) ) - s1++; + /* Trim left side */ + while ( (isspace (*s1)) && (s1 < s2) ) + s1++; - /* Copy finished string */ - strcpy (s, s1); - return s; + /* Copy finished string */ + strcpy (s, s1); + return s; } void @@ -86,7 +88,7 @@ parse_line(char *buff, char *name, char *value) i++; /* * Now the value - */ + */ j = 0; for ( ; i < MAXLEN; i++) if (buff[i] == '\'') @@ -96,5 +98,5 @@ parse_line(char *buff, char *name, char *value) else break; value[j] = '\0'; - trim(value); + trim(value); } diff --git a/config.h b/config.h index 139bfd32..ec23fff2 100644 --- a/config.h +++ b/config.h @@ -4,6 +4,7 @@ * */ -void parse_config(const char *config_file, char *cluster_name, int *node, char *service); +void parse_config(const char *config_file, char *cluster_name, int *node, + char *service); void parse_line(char *buff, char *name, char *value); char *trim(char *s); diff --git a/dbutils.c b/dbutils.c index 8287e1b0..bec62d66 100644 --- a/dbutils.c +++ b/dbutils.c @@ -12,19 +12,21 @@ PGconn * establishDBConnection(const char *conninfo, const bool exit_on_error) { PGconn *conn; - /* Make a connection to the database */ - conn = PQconnectdb(conninfo); - /* Check to see that the backend connection was successfully made */ - if ((PQstatus(conn) != CONNECTION_OK)) - { - fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + + /* Make a connection to the database */ + conn = PQconnectdb(conninfo); + + /* Check to see that the backend connection was successfully made */ + if ((PQstatus(conn) != CONNECTION_OK)) + { + fprintf(stderr, "Connection to database failed: %s", + PQerrorMessage(conn)); if (exit_on_error) { - PQfinish(conn); + PQfinish(conn); exit(1); } - } + } return conn; } @@ -34,29 +36,30 @@ establishDBConnection(const char *conninfo, const bool exit_on_error) bool is_standby(PGconn *conn) { - PGresult *res; + PGresult *res; bool result; - res = PQexec(conn, "SELECT pg_is_in_recovery()"); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "Can't query server mode: %s", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); + res = PQexec(conn, "SELECT pg_is_in_recovery()"); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "Can't query server mode: %s", PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); exit(1); - } + } if (strcmp(PQgetvalue(res, 0, 0), "f") == 0) result = false; else - result = true; + result = true; PQclear(res); return result; } -/* +/* * If postgreSQL version is 9 or superior returns the major version * if 8 or inferior returns an empty string */ @@ -69,20 +72,26 @@ pg_version(PGconn *conn) int major_version1; char *major_version2; - res = PQexec(conn, "WITH pg_version(ver) AS (SELECT split_part(version(), ' ', 2)) " - "SELECT split_part(ver, '.', 1), split_part(ver, '.', 2) FROM pg_version"); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { + res = PQexec(conn, + "WITH pg_version(ver) AS " + "(SELECT split_part(version(), ' ', 2)) " + "SELECT split_part(ver, '.', 1), split_part(ver, '.', 2) " + "FROM pg_version"); + + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { fprintf(stderr, "PQexec failed: %s", PQerrorMessage(conn)); - PQclear(res); + PQclear(res); PQfinish(conn); exit(1); - } - major_version1 = atoi(PQgetvalue(res, 0, 0)); - major_version2 = PQgetvalue(res, 0, 1); - PQclear(res); + } + + major_version1 = atoi(PQgetvalue(res, 0, 0)); + major_version2 = PQgetvalue(res, 0, 1); + PQclear(res); major_version = malloc(10); + if (major_version1 >= 9) { /* form a major version string */ @@ -96,27 +105,28 @@ pg_version(PGconn *conn) bool -guc_setted(PGconn *conn, const char *parameter, const char *op, const char *value) +guc_setted(PGconn *conn, const char *parameter, const char *op, + const char *value) { PGresult *res; char sqlquery[8192]; sprintf(sqlquery, "SELECT true FROM pg_settings " - " WHERE name = '%s' AND setting %s '%s'", - parameter, op, value); + " WHERE name = '%s' AND setting %s '%s'", + parameter, op, value); - res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { fprintf(stderr, "PQexec failed: %s", PQerrorMessage(conn)); - PQclear(res); + PQclear(res); PQfinish(conn); exit(1); - } + } if (PQntuples(res) == 0) { PQclear(res); - return false; + return false; } PQclear(res); @@ -131,72 +141,78 @@ get_cluster_size(PGconn *conn) const char *size; char sqlquery[8192]; - sprintf(sqlquery, "SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) " - " FROM pg_database "); + sprintf(sqlquery, + "SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) " + " FROM pg_database "); - res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { fprintf(stderr, "PQexec failed: %s", PQerrorMessage(conn)); - PQclear(res); + PQclear(res); PQfinish(conn); exit(1); - } - size = PQgetvalue(res, 0, 0); + } + size = PQgetvalue(res, 0, 0); PQclear(res); return size; } /* - * get a connection to master by reading repl_nodes, creating a connection + * get a connection to master by reading repl_nodes, creating a connection * to each node (one at a time) and finding if it is a master or a standby */ PGconn * -getMasterConnection(PGconn *standby_conn, int id, char *cluster, int *master_id) +getMasterConnection(PGconn *standby_conn, int id, char *cluster, + int *master_id) { PGconn *master_conn = NULL; - PGresult *res1; - PGresult *res2; - char sqlquery[8192]; + PGresult *res1; + PGresult *res2; + char sqlquery[8192]; char master_conninfo[8192]; int i; /* find all nodes belonging to this cluster */ sprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes " - " WHERE cluster = '%s' and id <> %d", - cluster, cluster, id); + " WHERE cluster = '%s' and id <> %d", + cluster, cluster, id); - res1 = PQexec(standby_conn, sqlquery); - if (PQresultStatus(res1) != PGRES_TUPLES_OK) - { - fprintf(stderr, "Can't get nodes info: %s\n", PQerrorMessage(standby_conn)); - PQclear(res1); + res1 = PQexec(standby_conn, sqlquery); + if (PQresultStatus(res1) != PGRES_TUPLES_OK) + { + fprintf(stderr, "Can't get nodes info: %s\n", + PQerrorMessage(standby_conn)); + PQclear(res1); PQfinish(standby_conn); exit(1); - } + } for (i = 0; i < PQntuples(res1); i++) - { + { /* initialize with the values of the current node being processed */ *master_id = atoi(PQgetvalue(res1, i, 0)); strcpy(master_conninfo, PQgetvalue(res1, i, 2)); master_conn = establishDBConnection(master_conninfo, false); + if (PQstatus(master_conn) != CONNECTION_OK) continue; - /* - * I can't use the is_standby() function here because on error that - * function closes the connection i pass and exit, but i still need to close - * standby_conn + /* + * I can't use the is_standby() function here because on error that + * function closes the connection i pass and exit, but i still need to + * close standby_conn */ - res2 = PQexec(master_conn, "SELECT pg_is_in_recovery()"); - if (PQresultStatus(res2) != PGRES_TUPLES_OK) - { - fprintf(stderr, "Can't get recovery state from this node: %s\n", PQerrorMessage(master_conn)); - PQclear(res2); + res2 = PQexec(master_conn, "SELECT pg_is_in_recovery()"); + + if (PQresultStatus(res2) != PGRES_TUPLES_OK) + { + fprintf(stderr, "Can't get recovery state from this node: %s\n", + PQerrorMessage(master_conn)); + PQclear(res2); PQfinish(master_conn); continue; - } + } /* if false, this is the master */ if (strcmp(PQgetvalue(res2, 0, 0), "f") == 0) @@ -212,17 +228,17 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, int *master_id) PQfinish(master_conn); *master_id = -1; } - } + } /* If we finish this loop without finding a master then - * we doesn't have the info or the master has failed (or we - * reached max_connections or superuser_reserved_connections, - * anything else i'm missing?), - * Probably we will need to check the error to know if we need - * to start failover procedure or just fix some situation on the - * standby. - */ + * we doesn't have the info or the master has failed (or we + * reached max_connections or superuser_reserved_connections, + * anything else I'm missing?). + * + * Probably we will need to check the error to know if we need + * to start failover procedure or just fix some situation on the + * standby. + */ PQclear(res1); return NULL; } - diff --git a/dbutils.h b/dbutils.h index a1f96a3f..e8383e57 100644 --- a/dbutils.h +++ b/dbutils.h @@ -5,8 +5,10 @@ */ PGconn *establishDBConnection(const char *conninfo, const bool exit_on_error); -bool is_standby(PGconn *conn); +bool is_standby(PGconn *conn); char *pg_version(PGconn *conn); -bool guc_setted(PGconn *conn, const char *parameter, const char *op, const char *value); -const char *get_cluster_size(PGconn *conn); -PGconn * getMasterConnection(PGconn *standby_conn, int id, char *cluster, int *master_id); +bool guc_setted(PGconn *conn, const char *parameter, const char *op, + const char *value); +const char *get_cluster_size(PGconn *conn); +PGconn * getMasterConnection(PGconn *standby_conn, int id, char *cluster, + int *master_id); diff --git a/repmgr.c b/repmgr.c index 18874c3b..950c6761 100644 --- a/repmgr.c +++ b/repmgr.c @@ -5,9 +5,9 @@ * Command interpreter for the repmgr * This module is a command-line utility to easily setup a cluster of * hot standby servers for an HA environment - * + * * Commands implemented are. - * MASTER REGISTER, STANDBY REGISTER, STANDBY CLONE, STANDBY FOLLOW, + * MASTER REGISTER, STANDBY REGISTER, STANDBY CLONE, STANDBY FOLLOW, * STANDBY PROMOTE */ @@ -23,18 +23,19 @@ #define RECOVERY_FILE "recovery.conf" #define RECOVERY_DONE_FILE "recovery.done" -#define NO_ACTION 0 /* Not a real action, just to initialize */ -#define MASTER_REGISTER 1 +#define NO_ACTION 0 /* Not a real action, just to initialize */ +#define MASTER_REGISTER 1 #define STANDBY_REGISTER 2 -#define STANDBY_CLONE 3 -#define STANDBY_PROMOTE 4 -#define STANDBY_FOLLOW 5 +#define STANDBY_CLONE 3 +#define STANDBY_PROMOTE 4 +#define STANDBY_FOLLOW 5 -#define QUERY_STR_LEN 8192 +#define QUERY_STR_LEN 8192 static void help(const char *progname); static bool create_recovery_file(const char *data_dir); -static int copy_remote_files(char *host, char *remote_user, char *remote_path, char *local_path, bool is_directory); +static int copy_remote_files(char *host, char *remote_user, char *remote_path, + char *local_path, bool is_directory); static bool check_parameters_for_action(const int action); static void do_master_register(void); @@ -54,7 +55,7 @@ char *username = NULL; char *dest_dir = NULL; char *config_file = NULL; char *remote_user = NULL; -char *wal_keep_segments = NULL; +char *wal_keep_segments = NULL; bool verbose = false; bool force = false; @@ -103,7 +104,8 @@ main(int argc, char **argv) } - while ((c = getopt_long(argc, argv, "d:h:p:U:D:f:R:w:F:v", long_options, &optindex)) != -1) + while ((c = getopt_long(argc, argv, "d:h:p:U:D:f:R:w:F:v", long_options, + &optindex)) != -1) { switch (c) { @@ -114,20 +116,20 @@ main(int argc, char **argv) host = optarg; break; case 'p': - masterport = optarg; - break; + masterport = optarg; + break; case 'U': username = optarg; break; case 'D': dest_dir = optarg; - break; + break; case 'f': config_file = optarg; - break; + break; case 'R': remote_user = optarg; - break; + break; case 'w': wal_keep_segments = optarg; break; @@ -138,69 +140,73 @@ main(int argc, char **argv) verbose = true; break; default: - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); } } - /* + /* * Now we need to obtain the action, this comes in one of these forms: - * MASTER REGISTER | - * STANDBY {REGISTER | CLONE [node] | PROMOTE | FOLLOW [node]} - * - * the node part is optional, if we receive it then we shouldn't - * have received a -h option - */ - if (optind < argc) + * MASTER REGISTER | + * STANDBY {REGISTER | CLONE [node] | PROMOTE | FOLLOW [node]} + * + * the node part is optional, if we receive it then we shouldn't + * have received a -h option + */ + if (optind < argc) { - server_mode = argv[optind++]; - if (strcasecmp(server_mode, "STANDBY") != 0 && strcasecmp(server_mode, "MASTER") != 0) + server_mode = argv[optind++]; + if (strcasecmp(server_mode, "STANDBY") != 0 && + strcasecmp(server_mode, "MASTER") != 0) { - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); - } + } } - if (optind < argc) + if (optind < argc) { - server_cmd = argv[optind++]; - if (strcasecmp(server_cmd, "REGISTER") == 0) + server_cmd = argv[optind++]; + if (strcasecmp(server_cmd, "REGISTER") == 0) { - /* - * we don't use this info in any other place so i will - * just execute the compare again instead of having an - * additional variable to hold a value that we will use - * no more - */ + /* + * we don't use this info in any other place so i will + * just execute the compare again instead of having an + * additional variable to hold a value that we will use + * no more + */ if (strcasecmp(server_mode, "MASTER") == 0) action = MASTER_REGISTER; - else if (strcasecmp(server_mode, "STANDBY") == 0) + else if (strcasecmp(server_mode, "STANDBY") == 0) action = STANDBY_REGISTER; } - else if (strcasecmp(server_cmd, "CLONE") == 0) + else if (strcasecmp(server_cmd, "CLONE") == 0) action = STANDBY_CLONE; - else if (strcasecmp(server_cmd, "PROMOTE") == 0) + else if (strcasecmp(server_cmd, "PROMOTE") == 0) action = STANDBY_PROMOTE; - else if (strcasecmp(server_cmd, "FOLLOW") == 0) + else if (strcasecmp(server_cmd, "FOLLOW") == 0) action = STANDBY_FOLLOW; else { - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); - } + } } /* For some actions we still can receive a last argument */ if (action == STANDBY_CLONE) { - if (optind < argc) + if (optind < argc) { if (host != NULL) { fprintf(stderr, _("Conflicting parameters you can't use -h while providing a node separately. Try \"%s --help\" for more information.\n"), progname); exit(1); - } - host = argv[optind++]; + } + host = argv[optind++]; } } @@ -211,7 +217,8 @@ main(int argc, char **argv) default: fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind + 1]); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); } @@ -230,24 +237,24 @@ main(int argc, char **argv) strcpy(wal_keep_segments, "5000"); } - if (dbname == NULL) - { - if (getenv("PGDATABASE")) - dbname = getenv("PGDATABASE"); - else if (getenv("PGUSER")) - dbname = getenv("PGUSER"); - else - dbname = "postgres"; - } + if (dbname == NULL) + { + if (getenv("PGDATABASE")) + dbname = getenv("PGDATABASE"); + else if (getenv("PGUSER")) + dbname = getenv("PGUSER"); + else + dbname = "postgres"; + } - keywords[2] = "user"; - values[2] = username; - keywords[3] = "dbname"; - values[3] = dbname; - keywords[4] = "application_name"; - values[4] = (char *) progname; - keywords[5] = NULL; - values[5] = NULL; + keywords[2] = "user"; + values[2] = username; + keywords[3] = "dbname"; + values[3] = dbname; + keywords[4] = "application_name"; + values[4] = (char *) progname; + keywords[5] = NULL; + values[5] = NULL; switch (action) { @@ -267,47 +274,49 @@ main(int argc, char **argv) do_standby_follow(); break; default: - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); } - - return 0; + + return 0; } -static void +static void do_master_register(void) { - PGconn *conn; + PGconn *conn; PGresult *res; - char sqlquery[QUERY_STR_LEN]; + char sqlquery[QUERY_STR_LEN]; - char myClusterName[MAXLEN]; - int myLocalId = -1; - char conninfo[MAXLEN]; + char myClusterName[MAXLEN]; + int myLocalId = -1; + char conninfo[MAXLEN]; bool schema_exists = false; const char *master_version = NULL; /* * Read the configuration file: repmgr.conf - */ + */ parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) + if (myLocalId == -1) { fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); + "Check the configuration file.\n"); exit(1); } - conn = establishDBConnection(conninfo, true); + conn = establishDBConnection(conninfo, true); /* master should be v9 or better */ master_version = pg_version(conn); if (strcmp(master_version, "") == 0) { PQfinish(conn); - fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), progname); + fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), + progname); return; } @@ -320,95 +329,101 @@ do_master_register(void) } /* Check if there is a schema for this cluster */ - sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", myClusterName); + sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", + myClusterName); res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) + if (PQresultStatus(res) != PGRES_TUPLES_OK) { - fprintf(stderr, "Can't get info about schemas: %s\n", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); - return; + fprintf(stderr, "Can't get info about schemas: %s\n", + PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return; } - + if (PQntuples(res) > 0) /* schema exists */ { if (!force) /* and we are not forcing so error */ { - fprintf(stderr, "Schema repmgr_%s already exists.", myClusterName); - PQclear(res); - PQfinish(conn); + fprintf(stderr, "Schema repmgr_%s already exists.", myClusterName); + PQclear(res); + PQfinish(conn); return; } schema_exists = true; } PQclear(res); - + if (!schema_exists) { /* ok, create the schema */ sprintf(sqlquery, "CREATE SCHEMA repmgr_%s", myClusterName); - if (!PQexec(conn, sqlquery)) + if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot create the schema repmgr_%s: %s\n", - myClusterName, PQerrorMessage(conn)); - PQfinish(conn); - return; - } - - /* ... the tables */ - sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( " - " id integer primary key, " - " cluster text not null, " - " conninfo text not null)", myClusterName); - if (!PQexec(conn, sqlquery)) - { - fprintf(stderr, "Cannot create the table repmgr_%s.repl_nodes: %s\n", - myClusterName, PQerrorMessage(conn)); - PQfinish(conn); - return; - } - - sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_monitor ( " - " primary_node INTEGER NOT NULL, " - " standby_node INTEGER NOT NULL, " - " last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, " - " last_wal_primary_location TEXT NOT NULL, " - " last_wal_standby_location TEXT NOT NULL, " - " replication_lag BIGINT NOT NULL, " - " apply_lag BIGINT NOT NULL) ", myClusterName); - if (!PQexec(conn, sqlquery)) - { - fprintf(stderr, "Cannot create the table repmgr_%s.repl_monitor: %s\n", - myClusterName, PQerrorMessage(conn)); - PQfinish(conn); + myClusterName, PQerrorMessage(conn)); + PQfinish(conn); return; } - /* and the view */ - sprintf(sqlquery, "CREATE VIEW repmgr_%s.repl_status AS " - " WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node " - " ORDER BY last_monitor_time desc) " - " FROM repmgr_%s.repl_monitor) " - " SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, " - " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " - " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " - " FROM monitor_info a " - " WHERE row_number = 1", myClusterName, myClusterName); - if (!PQexec(conn, sqlquery)) + /* ... the tables */ + sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( " + " id integer primary key, " + " cluster text not null, " + " conninfo text not null)", myClusterName); + if (!PQexec(conn, sqlquery)) { - fprintf(stderr, "Cannot create the view repmgr_%s.repl_status: %s\n", - myClusterName, PQerrorMessage(conn)); - PQfinish(conn); + fprintf(stderr, + "Cannot create the table repmgr_%s.repl_nodes: %s\n", + myClusterName, PQerrorMessage(conn)); + PQfinish(conn); + return; + } + + sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_monitor ( " + " primary_node INTEGER NOT NULL, " + " standby_node INTEGER NOT NULL, " + " last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, " + " last_wal_primary_location TEXT NOT NULL, " + " last_wal_standby_location TEXT NOT NULL, " + " replication_lag BIGINT NOT NULL, " + " apply_lag BIGINT NOT NULL) ", + myClusterName); + if (!PQexec(conn, sqlquery)) + { + fprintf(stderr, + "Cannot create the table repmgr_%s.repl_monitor: %s\n", + myClusterName, PQerrorMessage(conn)); + PQfinish(conn); + return; + } + + /* and the view */ + sprintf(sqlquery, "CREATE VIEW repmgr_%s.repl_status AS " + " WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node " + " ORDER BY last_monitor_time desc) " + " FROM repmgr_%s.repl_monitor) " + " SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, " + " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " + " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " + " FROM monitor_info a " + " WHERE row_number = 1", myClusterName, myClusterName); + if (!PQexec(conn, sqlquery)) + { + fprintf(stderr, + "Cannot create the view repmgr_%s.repl_status: %s\n", + myClusterName, PQerrorMessage(conn)); + PQfinish(conn); return; } } else { PGconn *master_conn; - int id; + int id; /* Ensure there isn't any other master already registered */ - master_conn = getMasterConnection(conn, myLocalId, myClusterName, &id); + master_conn = getMasterConnection(conn, myLocalId, myClusterName, &id); if (master_conn != NULL) { PQfinish(master_conn); @@ -420,72 +435,73 @@ do_master_register(void) /* Now register the master */ if (force) { - sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " - " WHERE id = %d", - myClusterName, myLocalId); + sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " + " WHERE id = %d", + myClusterName, myLocalId); - if (!PQexec(conn, sqlquery)) - { - fprintf(stderr, "Cannot delete node details, %s\n", - PQerrorMessage(conn)); - PQfinish(conn); + if (!PQexec(conn, sqlquery)) + { + fprintf(stderr, "Cannot delete node details, %s\n", + PQerrorMessage(conn)); + PQfinish(conn); return; - } + } } - sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " - "VALUES (%d, '%s', '%s')", - myClusterName, myLocalId, myClusterName, conninfo); - - if (!PQexec(conn, sqlquery)) - { - fprintf(stderr, "Cannot insert node details, %s\n", - PQerrorMessage(conn)); - PQfinish(conn); + sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " + "VALUES (%d, '%s', '%s')", + myClusterName, myLocalId, myClusterName, conninfo); + + if (!PQexec(conn, sqlquery)) + { + fprintf(stderr, "Cannot insert node details, %s\n", + PQerrorMessage(conn)); + PQfinish(conn); return; - } + } PQfinish(conn); return; } -static void +static void do_standby_register(void) { - PGconn *conn; + PGconn *conn; PGconn *master_conn; int master_id; PGresult *res; - char sqlquery[QUERY_STR_LEN]; + char sqlquery[QUERY_STR_LEN]; - char myClusterName[MAXLEN]; - int myLocalId = -1; - char conninfo[MAXLEN]; + char myClusterName[MAXLEN]; + int myLocalId = -1; + char conninfo[MAXLEN]; const char *master_version = NULL; const char *standby_version = NULL; /* * Read the configuration file: repmgr.conf - */ + */ parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) + if (myLocalId == -1) { fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); + "Check the configuration file.\n"); exit(1); } - conn = establishDBConnection(conninfo, true); + conn = establishDBConnection(conninfo, true); /* should be v9 or better */ standby_version = pg_version(conn); if (strcmp(standby_version, "") == 0) { PQfinish(conn); - fprintf(stderr, _("%s needs standby to be PostgreSQL 9.0 or better\n"), progname); + fprintf(stderr, _("%s needs standby to be PostgreSQL 9.0 or better\n"), + progname); return; } @@ -498,27 +514,30 @@ do_standby_register(void) } /* Check if there is a schema for this cluster */ - sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", myClusterName); + sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", + myClusterName); res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) + if (PQresultStatus(res) != PGRES_TUPLES_OK) { - fprintf(stderr, "Can't get info about tablespaces: %s\n", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); - return; + fprintf(stderr, "Can't get info about tablespaces: %s\n", + PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return; } - + if (PQntuples(res) == 0) /* schema doesn't exists */ { - fprintf(stderr, "Schema repmgr_%s doesn't exists.", myClusterName); - PQclear(res); - PQfinish(conn); + fprintf(stderr, "Schema repmgr_%s doesn't exists.", myClusterName); + PQclear(res); + PQfinish(conn); return; } PQclear(res); - + /* check if there is a master in this cluster */ - master_conn = getMasterConnection(conn, myLocalId, myClusterName, &master_id); + master_conn = getMasterConnection(conn, myLocalId, myClusterName, + &master_id); if (!master_conn) return; @@ -528,7 +547,8 @@ do_standby_register(void) { PQfinish(conn); PQfinish(master_conn); - fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), progname); + fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), + progname); return; } @@ -537,8 +557,8 @@ do_standby_register(void) { PQfinish(conn); PQfinish(master_conn); - fprintf(stderr, _("%s needs versions of both master (%s) and standby (%s) to match.\n"), - progname, master_version, standby_version); + fprintf(stderr, _("%s needs versions of both master (%s) and standby (%s) to match.\n"), + progname, master_version, standby_version); return; } @@ -546,32 +566,32 @@ do_standby_register(void) /* Now register the standby */ if (force) { - sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " - " WHERE id = %d", - myClusterName, myLocalId); + sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " + " WHERE id = %d", + myClusterName, myLocalId); - if (!PQexec(master_conn, sqlquery)) - { - fprintf(stderr, "Cannot delete node details, %s\n", - PQerrorMessage(master_conn)); - PQfinish(master_conn); - PQfinish(conn); + if (!PQexec(master_conn, sqlquery)) + { + fprintf(stderr, "Cannot delete node details, %s\n", + PQerrorMessage(master_conn)); + PQfinish(master_conn); + PQfinish(conn); return; - } + } } - sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " - "VALUES (%d, '%s', '%s')", - myClusterName, myLocalId, myClusterName, conninfo); - - if (!PQexec(master_conn, sqlquery)) - { - fprintf(stderr, "Cannot insert node details, %s\n", - PQerrorMessage(master_conn)); - PQfinish(master_conn); - PQfinish(conn); + sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " + "VALUES (%d, '%s', '%s')", + myClusterName, myLocalId, myClusterName, conninfo); + + if (!PQexec(master_conn, sqlquery)) + { + fprintf(stderr, "Cannot insert node details, %s\n", + PQerrorMessage(master_conn)); + PQfinish(master_conn); + PQfinish(conn); return; - } + } PQfinish(master_conn); PQfinish(conn); @@ -579,12 +599,12 @@ do_standby_register(void) } -static void +static void do_standby_clone(void) { - PGconn *conn; + PGconn *conn; PGresult *res; - char sqlquery[QUERY_STR_LEN]; + char sqlquery[QUERY_STR_LEN]; int r = 0; int i; @@ -597,8 +617,8 @@ do_standby_clone(void) char master_control_file[MAXLEN]; char local_control_file[MAXLEN]; - const char *first_wal_segment = NULL; - const char *last_wal_segment = NULL; + const char *first_wal_segment = NULL; + const char *last_wal_segment = NULL; const char *master_version = NULL; @@ -610,48 +630,48 @@ do_standby_clone(void) } /* Check this directory could be used as a PGDATA dir */ - switch (check_dir(dest_dir)) - { - case 0: - /* dest_dir not there, must create it */ + switch (check_dir(dest_dir)) + { + case 0: + /* dest_dir not there, must create it */ if (verbose) - printf(_("creating directory %s ... "), dest_dir); - fflush(stdout); + printf(_("creating directory %s ... "), dest_dir); + fflush(stdout); - if (!create_directory(dest_dir)) + if (!create_directory(dest_dir)) { - fprintf(stderr, _("%s: couldn't create directory %s ... "), + fprintf(stderr, _("%s: couldn't create directory %s ... "), progname, dest_dir); return; } - break; - case 1: - /* Present but empty, fix permissions and use it */ + break; + case 1: + /* Present but empty, fix permissions and use it */ if (verbose) - printf(_("fixing permissions on existing directory %s ... "), - dest_dir); - fflush(stdout); + printf(_("fixing permissions on existing directory %s ... "), + dest_dir); + fflush(stdout); if (!set_directory_permissions(dest_dir)) - { - fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), - progname, dest_dir, strerror(errno)); + { + fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), + progname, dest_dir, strerror(errno)); return; - } - break; - case 2: - /* Present and not empty */ - fprintf(stderr, - _("%s: directory \"%s\" exists but is not empty\n"), - progname, dest_dir); + } + break; + case 2: + /* Present and not empty */ + fprintf(stderr, + _("%s: directory \"%s\" exists but is not empty\n"), + progname, dest_dir); - pg_dir = is_pg_dir(dest_dir); - if (pg_dir && !force) + pg_dir = is_pg_dir(dest_dir); + if (pg_dir && !force) { fprintf(stderr, _("\nThis looks like a PostgreSQL directroy.\n" - "If you are sure you want to clone here, " - "please check there is no PostgreSQL server " - "running and use the --force option\n")); + "If you are sure you want to clone here, " + "please check there is no PostgreSQL server " + "running and use the --force option\n")); return; } else if (pg_dir && force) @@ -659,35 +679,36 @@ do_standby_clone(void) /* Let it continue */ break; } - else + else return; - default: - /* Trouble accessing directory */ - fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"), - progname, dest_dir, strerror(errno)); - } + default: + /* Trouble accessing directory */ + fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"), + progname, dest_dir, strerror(errno)); + } - /* Connection parameters for master only */ - keywords[0] = "host"; - values[0] = host; - keywords[1] = "port"; - values[1] = masterport; + /* Connection parameters for master only */ + keywords[0] = "host"; + values[0] = host; + keywords[1] = "port"; + values[1] = masterport; /* We need to connect to check configuration and start a backup */ - conn = PQconnectdbParams(keywords, values, true); - if (!conn) - { - fprintf(stderr, _("%s: could not connect to master\n"), - progname); - return; - } + conn = PQconnectdbParams(keywords, values, true); + if (!conn) + { + fprintf(stderr, _("%s: could not connect to master\n"), + progname); + return; + } /* primary should be v9 or better */ master_version = pg_version(conn); if (strcmp(master_version, "") == 0) { PQfinish(conn); - fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), progname); + fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), + progname); return; } @@ -703,19 +724,19 @@ do_standby_clone(void) if (!guc_setted(conn, "wal_level", "=", "hot_standby")) { PQfinish(conn); - fprintf(stderr, _("%s needs parameter 'wal_level' to be set to 'hot_standby'\n"), progname); + fprintf(stderr, _("%s needs parameter 'wal_level' to be set to 'hot_standby'\n"), progname); return; } if (!guc_setted(conn, "wal_keep_segments", ">=", wal_keep_segments)) { PQfinish(conn); - fprintf(stderr, _("%s needs parameter 'wal_keep_segments' to be set to %s or greater\n"), wal_keep_segments, progname); + fprintf(stderr, _("%s needs parameter 'wal_keep_segments' to be set to %s or greater\n"), wal_keep_segments, progname); return; } if (!guc_setted(conn, "archive_mode", "=", "on")) { PQfinish(conn); - fprintf(stderr, _("%s needs parameter 'archive_mode' to be set to 'on'\n"), progname); + fprintf(stderr, _("%s needs parameter 'archive_mode' to be set to 'on'\n"), progname); return; } @@ -724,13 +745,13 @@ do_standby_clone(void) /* 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')"); - res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { - fprintf(stderr, "Can't get info about tablespaces: %s\n", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); - return; + fprintf(stderr, "Can't get info about tablespaces: %s\n", PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return; } for (i = 0; i < PQntuples(res); i++) { @@ -738,74 +759,77 @@ do_standby_clone(void) strcpy(tblspc_dir, PQgetvalue(res, i, 0)); /* Check this directory could be used as a PGDATA dir */ - switch (check_dir(tblspc_dir)) - { - case 0: - /* tblspc_dir not there, must create it */ + switch (check_dir(tblspc_dir)) + { + case 0: + /* tblspc_dir not there, must create it */ if (verbose) - printf(_("creating directory \"%s\"... "), tblspc_dir); - fflush(stdout); - - if (!create_directory(tblspc_dir)) + printf(_("creating directory \"%s\"... "), tblspc_dir); + fflush(stdout); + + if (!create_directory(tblspc_dir)) { - fprintf(stderr, _("%s: couldn't create directory \"%s\"... "), + fprintf(stderr, + _("%s: couldn't create directory \"%s\"... "), progname, tblspc_dir); PQclear(res); PQfinish(conn); return; } - break; - case 1: - /* Present but empty, fix permissions and use it */ + break; + case 1: + /* Present but empty, fix permissions and use it */ if (verbose) - printf(_("fixing permissions on existing directory \"%s\"... "), - tblspc_dir); - fflush(stdout); - - if (!set_directory_permissions(tblspc_dir)) - { - fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), - progname, tblspc_dir, strerror(errno)); + printf(_("fixing permissions on existing directory \"%s\"... "), + tblspc_dir); + fflush(stdout); + + if (!set_directory_permissions(tblspc_dir)) + { + fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), + progname, tblspc_dir, strerror(errno)); PQclear(res); PQfinish(conn); return; - } - break; - case 2: - /* Present and not empty */ - if (!force) - { + } + break; + case 2: + /* Present and not empty */ + if (!force) + { + fprintf( + stderr, + _("%s: directory \"%s\" exists but is not empty\n"), + progname, tblspc_dir); + PQclear(res); + PQfinish(conn); + return; + } + default: + /* Trouble accessing directory */ fprintf(stderr, - _("%s: directory \"%s\" exists but is not empty\n"), - progname, tblspc_dir); + _("%s: could not access directory \"%s\": %s\n"), + progname, tblspc_dir, strerror(errno)); PQclear(res); PQfinish(conn); - return; - } - default: - /* Trouble accessing directory */ - fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"), - progname, tblspc_dir, strerror(errno)); - PQclear(res); - PQfinish(conn); - return; + return; } } - + fprintf(stderr, "Starting backup...\n"); - + /* Get the data directory full path and the configuration files location */ sprintf(sqlquery, "SELECT name, setting " - " FROM pg_settings " - " WHERE name IN ('data_directory', 'config_file', 'hba_file', 'ident_file')"); - res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "Can't get info about data directory and configuration files: %s\n", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); - return; - } + " FROM pg_settings " + " WHERE name IN ('data_directory', 'config_file', 'hba_file', 'ident_file')"); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "Can't get info about data directory and configuration files: %s\n", PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return; + } for (i = 0; i < PQntuples(res); i++) { if (strcmp(PQgetvalue(res, i, 0), "data_directory") == 0) @@ -819,146 +843,162 @@ do_standby_clone(void) else fprintf(stderr, _("uknown parameter: %s"), PQgetvalue(res, i, 0)); } - PQclear(res); + PQclear(res); - /* - * 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 - */ + */ sprintf(sqlquery, "SELECT pg_xlogfile_name(pg_start_backup('repmgr_standby_clone_%ld'))", time(NULL)); - res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "Can't start backup: %s\n", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); - return; - } + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "Can't start backup: %s\n", PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return; + } first_wal_segment = PQgetvalue(res, 0, 0); PQclear(res); /* - * 1) first move global/pg_control + * 1) first move global/pg_control * - * 2) then move data_directory ommiting the files we have already moved and pg_xlog - * content + * 2) then move data_directory ommiting the files we have already moved and + * pg_xlog content * - * 3) finally We need to backup configuration files (that could be on other directories, debian - * like systems likes to do that), so look at config_file, hba_file and ident_file but we - * can omit external_pid_file ;) + * 3) finally We need to backup configuration files (that could be on other + * directories, debian like systems likes to do that), so look at + * config_file, hba_file and ident_file but we can omit + * external_pid_file ;) * * On error we need to return but before that execute pg_stop_backup() */ /* need to create the global sub directory */ - sprintf(master_control_file, "%s/global/pg_control", master_data_directory); + sprintf(master_control_file, "%s/global/pg_control", + master_data_directory); sprintf(local_control_file, "%s/global", dest_dir); if (!create_directory(local_control_file)) - { - fprintf(stderr, _("%s: couldn't create directory %s ... "), - progname, dest_dir); + { + fprintf(stderr, _("%s: couldn't create directory %s ... "), + progname, dest_dir); goto stop_backup; } - r = copy_remote_files(host, remote_user, master_control_file, local_control_file, false); + r = copy_remote_files(host, remote_user, master_control_file, + local_control_file, false); if (r != 0) goto stop_backup; - r = copy_remote_files(host, remote_user, master_data_directory, dest_dir, true); + r = copy_remote_files(host, remote_user, master_data_directory, dest_dir, + true); if (r != 0) goto stop_backup; - /* - * Copy tablespace locations, i'm doing this separately because i couldn't find and appropiate - * rsync option but besides we could someday make all these rsync happen concurrently - */ - sprintf(sqlquery, "select spclocation from pg_tablespace where spcname not in ('pg_default', 'pg_global')"); - res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "Can't get info about tablespaces: %s\n", PQerrorMessage(conn)); - PQclear(res); - goto stop_backup; - } - for (i = 0; i < PQntuples(res); i++) + /* + * Copy tablespace locations, i'm doing this separately because i couldn't + * find and appropiate rsync option but besides we could someday make all + * these rsync happen concurrently + */ + sprintf(sqlquery, "select spclocation from pg_tablespace where spcname not in ('pg_default', 'pg_global')"); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) { - r = copy_remote_files(host, remote_user, PQgetvalue(res, i, 0), PQgetvalue(res, i, 0), true); + fprintf(stderr, "Can't get info about tablespaces: %s\n", + PQerrorMessage(conn)); + PQclear(res); + goto stop_backup; + } + for (i = 0; i < PQntuples(res); i++) + { + r = copy_remote_files(host, remote_user, PQgetvalue(res, i, 0), + PQgetvalue(res, i, 0), true); if (r != 0) goto stop_backup; } - r = copy_remote_files(host, remote_user, master_config_file, dest_dir, false); + r = copy_remote_files(host, remote_user, master_config_file, dest_dir, + false); if (r != 0) goto stop_backup; - r = copy_remote_files(host, remote_user, master_hba_file, dest_dir, false); + r = copy_remote_files(host, remote_user, master_hba_file, dest_dir, false); if (r != 0) goto stop_backup; - r = copy_remote_files(host, remote_user, master_ident_file, dest_dir, false); + r = copy_remote_files(host, remote_user, master_ident_file, dest_dir, + false); if (r != 0) goto stop_backup; stop_backup: - /* inform the master that we have finished the backup */ - conn = PQconnectdbParams(keywords, values, true); - if (!conn) - { - fprintf(stderr, _("%s: could not connect to master\n"), - progname); - return; - } + /* inform the master that we have finished the backup */ + conn = PQconnectdbParams(keywords, values, true); + if (!conn) + { + fprintf(stderr, _("%s: could not connect to master\n"), + progname); + return; + } - fprintf(stderr, "Finishing backup...\n"); + fprintf(stderr, "Finishing backup...\n"); sprintf(sqlquery, "SELECT pg_xlogfile_name(pg_stop_backup())"); - res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "Can't stop backup: %s\n", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); - return; - } + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "Can't stop backup: %s\n", PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return; + } last_wal_segment = PQgetvalue(res, 0, 0); - PQclear(res); - PQfinish(conn); + PQclear(res); + PQfinish(conn); /* Now, if the rsync failed then exit */ if (r != 0) return; if (verbose) - printf(_("%s requires primary to keep WAL files %s until at least %s\n"), - progname, first_wal_segment, last_wal_segment); + printf( + _("%s requires primary to keep WAL files %s until at least %s\n"), + progname, first_wal_segment, last_wal_segment); - /* we need to create the pg_xlog sub directory too, i'm reusing a variable here */ + /* + * We need to create the pg_xlog sub directory too, I'm reusing a variable + * here. + */ sprintf(local_control_file, "%s/pg_xlog", dest_dir); if (!create_directory(local_control_file)) - { - fprintf(stderr, _("%s: couldn't create directory %s, you will need to do it manually...\n"), - progname, dest_dir); + { + fprintf(stderr, _("%s: couldn't create directory %s, you will need to do it manually...\n"), + progname, dest_dir); } /* Finally, write the recovery.conf file */ create_recovery_file(dest_dir); - /* We don't start the service because we still may want to move the directory */ + /* + * We don't start the service because we still may want to move the + * directory + */ return; } -static void +static void do_standby_promote(void) { - PGconn *conn; + PGconn *conn; PGresult *res; - char sqlquery[QUERY_STR_LEN]; - char script[QUERY_STR_LEN]; + char sqlquery[QUERY_STR_LEN]; + char script[QUERY_STR_LEN]; - char myClusterName[MAXLEN]; - int myLocalId = -1; - char conninfo[MAXLEN]; + char myClusterName[MAXLEN]; + int myLocalId = -1; + char conninfo[MAXLEN]; PGconn *old_master_conn; int old_master_id; @@ -972,36 +1012,39 @@ do_standby_promote(void) /* * Read the configuration file: repmgr.conf - */ + */ parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) + if (myLocalId == -1) { fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); + "Check the configuration file.\n"); exit(1); } /* We need to connect to check configuration */ - conn = establishDBConnection(conninfo, true); + conn = establishDBConnection(conninfo, true); /* we need v9 or better */ standby_version = pg_version(conn); if (strcmp(standby_version, "") == 0) { PQfinish(conn); - fprintf(stderr, _("%s needs standby to be PostgreSQL 9.0 or better\n"), progname); + fprintf(stderr, _("%s needs standby to be PostgreSQL 9.0 or better\n"), + progname); return; } /* Check we are in a standby node */ if (!is_standby(conn)) { - fprintf(stderr, "repmgr: The command should be executed in a standby node\n"); + fprintf(stderr, + "repmgr: The command should be executed in a standby node\n"); return; } /* we also need to check if there isn't any master already */ - old_master_conn = getMasterConnection(conn, myLocalId, myClusterName, &old_master_id); + old_master_conn = getMasterConnection(conn, myLocalId, myClusterName, + &old_master_id); if (old_master_conn != NULL) { PQfinish(old_master_conn); @@ -1011,21 +1054,22 @@ do_standby_promote(void) if (verbose) printf(_("\n%s: Promoting standby...\n"), progname); - + /* Get the data directory full path and the last subdirectory */ sprintf(sqlquery, "SELECT setting " - " FROM pg_settings WHERE name = 'data_directory'"); - res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "Can't get info about data directory: %s\n", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); - return; - } + " FROM pg_settings WHERE name = 'data_directory'"); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "Can't get info about data directory: %s\n", + PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return; + } strcpy(data_dir, PQgetvalue(res, 0, 0)); - PQclear(res); - PQfinish(conn); + PQclear(res); + PQfinish(conn); sprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE); sprintf(recovery_done_path, "%s/%s", data_dir, RECOVERY_DONE_FILE); @@ -1034,39 +1078,41 @@ do_standby_promote(void) /* We assume the pg_ctl script is in the PATH */ sprintf(script, "pg_ctl -D %s -m fast restart", data_dir); r = system(script); - if (r != 0) - { - fprintf(stderr, "Can't restart service\n"); + if (r != 0) + { + fprintf(stderr, "Can't restart service\n"); return; - } + } /* reconnect to check we got promoted */ - /* - * XXX i'm removing this because it gives an annoying message saying couldn't connect - * but is just the server starting up -* conn = establishDBConnection(conninfo, true); -* if (is_standby(conn)) -* fprintf(stderr, "\n%s: STANDBY PROMOTE failed, this is still a standby node.\n", progname); -* else -* fprintf(stderr, "\n%s: you should REINDEX any hash indexes you have.\n", progname); -* PQfinish(conn); - */ + + /* + * XXX i'm removing this because it gives an annoying message saying + * couldn't connect but is just the server starting up + * + * conn = establishDBConnection(conninfo, true); + * if (is_standby(conn)) + * fprintf(stderr, "\n%s: STANDBY PROMOTE failed, this is still a standby node.\n", progname); + * else + * fprintf(stderr, "\n%s: you should REINDEX any hash indexes you have.\n", progname); + * PQfinish(conn); + */ return; } -static void +static void do_standby_follow(void) { - PGconn *conn; + PGconn *conn; PGresult *res; - char sqlquery[QUERY_STR_LEN]; - char script[QUERY_STR_LEN]; + char sqlquery[QUERY_STR_LEN]; + char script[QUERY_STR_LEN]; - char myClusterName[MAXLEN]; - int myLocalId = -1; - char conninfo[MAXLEN]; + char myClusterName[MAXLEN]; + int myLocalId = -1; + char conninfo[MAXLEN]; PGconn *master_conn; int master_id; @@ -1077,19 +1123,17 @@ do_standby_follow(void) const char *master_version = NULL; const char *standby_version = NULL; - /* - * Read the configuration file: repmgr.conf - */ + /* Read the configuration file: repmgr.conf */ parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) + if (myLocalId == -1) { fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); + "Check the configuration file.\n"); exit(1); } /* We need to connect to check configuration */ - conn = establishDBConnection(conninfo, true); + conn = establishDBConnection(conninfo, true); /* Check we are in a standby node */ if (!is_standby(conn)) @@ -1103,12 +1147,13 @@ do_standby_follow(void) if (strcmp(standby_version, "") == 0) { PQfinish(conn); - fprintf(stderr, _("\n%s needs standby to be PostgreSQL 9.0 or better\n"), progname); + fprintf(stderr, _("\n%s needs standby to be PostgreSQL 9.0 or better\n"), progname); return; } /* we also need to check if there is any master in the cluster */ - master_conn = getMasterConnection(conn, myLocalId, myClusterName, &master_id); + master_conn = getMasterConnection(conn, myLocalId, myClusterName, + &master_id); if (master_conn == NULL) { PQfinish(conn); @@ -1120,7 +1165,8 @@ do_standby_follow(void) if (is_standby(master_conn)) { PQfinish(conn); - fprintf(stderr, "%s: The node to follow should be a master\n", progname); + fprintf(stderr, "%s: The node to follow should be a master\n", + progname); return; } @@ -1130,7 +1176,8 @@ do_standby_follow(void) { PQfinish(conn); PQfinish(master_conn); - fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), progname); + fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), + progname); return; } @@ -1139,14 +1186,14 @@ do_standby_follow(void) { PQfinish(conn); PQfinish(master_conn); - fprintf(stderr, _("%s needs versions of both master (%s) and standby (%s) to match.\n"), - progname, master_version, standby_version); + fprintf(stderr, _("%s needs versions of both master (%s) and standby (%s) to match.\n"), + progname, master_version, standby_version); return; } - /* - * set the host and masterport variables with the master ones - * before closing the connection because we will need them to + /* + * set the host and masterport variables with the master ones + * before closing the connection because we will need them to * recreate the recovery.conf file */ host = malloc(20); @@ -1157,72 +1204,74 @@ do_standby_follow(void) if (verbose) printf(_("\n%s: Changing standby's master...\n"), progname); - + /* Get the data directory full path */ sprintf(sqlquery, "SELECT setting " - " FROM pg_settings WHERE name = 'data_directory'"); - res = PQexec(conn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "Can't get info about data directory: %s\n", PQerrorMessage(conn)); - PQclear(res); - PQfinish(conn); - return; - } + " FROM pg_settings WHERE name = 'data_directory'"); + res = PQexec(conn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "Can't get info about data directory: %s\n", + PQerrorMessage(conn)); + PQclear(res); + PQfinish(conn); + return; + } strcpy(data_dir, PQgetvalue(res, 0, 0)); - PQclear(res); - PQfinish(conn); + PQclear(res); + PQfinish(conn); /* write the recovery.conf file */ if (!create_recovery_file(data_dir)) - return; + return; /* Finally, restart the service */ /* We assume the pg_ctl script is in the PATH */ sprintf(script, "pg_ctl -D %s -m fast restart", data_dir); r = system(script); - if (r != 0) - { - fprintf(stderr, "Can't restart service\n"); + if (r != 0) + { + fprintf(stderr, "Can't restart service\n"); return; - } + } return; } -static void +static void help(const char *progname) { - printf(_("\n%s: Replicator manager \n"), progname); - printf(_("Usage:\n")); - printf(_(" %s [OPTIONS] master {register}\n"), progname); - printf(_(" %s [OPTIONS] standby {register|clone|promote|follow}\n"), progname); - printf(_("\nGeneral options:\n")); - printf(_(" --help show this help, then exit\n")); - printf(_(" --version output version information, then exit\n")); - printf(_(" --verbose output verbose activity information\n")); + printf(_("\n%s: Replicator manager \n"), progname); + printf(_("Usage:\n")); + printf(_(" %s [OPTIONS] master {register}\n"), progname); + printf(_(" %s [OPTIONS] standby {register|clone|promote|follow}\n"), + progname); + printf(_("\nGeneral options:\n")); + printf(_(" --help show this help, then exit\n")); + printf(_(" --version output version information, then exit\n")); + printf(_(" --verbose output verbose activity information\n")); printf(_("\nConnection options:\n")); - printf(_(" -d, --dbname=DBNAME database to connect to\n")); - printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); - printf(_(" -p, --port=PORT database server port\n")); - printf(_(" -U, --username=USERNAME database user name to connect as\n")); + printf(_(" -d, --dbname=DBNAME database to connect to\n")); + printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); + printf(_(" -p, --port=PORT database server port\n")); + printf(_(" -U, --username=USERNAME database user name to connect as\n")); printf(_("\nConfiguration options:\n")); - printf(_(" -D, --data-dir=DIR local directory where the files will be copied to\n")); - printf(_(" -f, --config_file=PATH path to the configuration file\n")); - printf(_(" -R, --remote-user=USERNAME database server username for rsync\n")); - printf(_(" -w, --wal-keep-segments=VALUE minimum value for the GUC wal_keep_segments (default: 5000)\n")); - printf(_(" -F, --force force potentially dangerous operations to happen\n")); - + printf(_(" -D, --data-dir=DIR local directory where the files will be copied to\n")); + printf(_(" -f, --config_file=PATH path to the configuration file\n")); + printf(_(" -R, --remote-user=USERNAME database server username for rsync\n")); + printf(_(" -w, --wal-keep-segments=VALUE minimum value for the GUC wal_keep_segments (default: 5000)\n")); + printf(_(" -F, --force force potentially dangerous operations to happen\n")); + printf(_("\n%s performs some tasks like clone a node, promote it "), progname); - printf(_("or making follow another node and then exits.\n")); - printf(_("COMMANDS:\n")); - printf(_(" master register - registers the master in a cluster\n")); - printf(_(" standby register - registers a standby in a cluster\n")); - printf(_(" standby clone [node] - allows creation of a new standby\n")); - printf(_(" standby promote - allows manual promotion of a specific standby into a ")); - printf(_("new master in the event of a failover\n")); - printf(_(" standby follow - allows the standby to re-point itself to a new master\n")); + printf(_("or making follow another node and then exits.\n")); + printf(_("COMMANDS:\n")); + printf(_(" master register - registers the master in a cluster\n")); + printf(_(" standby register - registers a standby in a cluster\n")); + printf(_(" standby clone [node] - allows creation of a new standby\n")); + printf(_(" standby promote - allows manual promotion of a specific standby into a ")); + printf(_("new master in the event of a failover\n")); + printf(_(" standby follow - allows the standby to re-point itself to a new master\n")); } @@ -1235,45 +1284,47 @@ create_recovery_file(const char *data_dir) sprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE); - recovery_file = fopen(recovery_file_path, "w"); - if (recovery_file == NULL) - { - fprintf(stderr, "could not create recovery.conf file, it could be necesary to create it manually\n"); + recovery_file = fopen(recovery_file_path, "w"); + if (recovery_file == NULL) + { + fprintf(stderr, "could not create recovery.conf file, it could be necesary to create it manually\n"); return false; - } + } sprintf(line, "standby_mode = 'on'\n"); if (fputs(line, recovery_file) == EOF) - { - fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n"); - fclose(recovery_file); + { + fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n"); + fclose(recovery_file); return false; - } + } - sprintf(line, "primary_conninfo = 'host=%s port=%s'\n", host, ((masterport==NULL) ? "5432" : masterport)); + sprintf(line, "primary_conninfo = 'host=%s port=%s'\n", host, + ((masterport==NULL) ? "5432" : masterport)); if (fputs(line, recovery_file) == EOF) - { - fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n"); - fclose(recovery_file); + { + fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n"); + fclose(recovery_file); return false; - } + } - /*FreeFile(recovery_file);*/ - fclose(recovery_file); + /*FreeFile(recovery_file);*/ + fclose(recovery_file); return true; } static int -copy_remote_files(char *host, char *remote_user, char *remote_path, char *local_path, bool is_directory) +copy_remote_files(char *host, char *remote_user, char *remote_path, + char *local_path, bool is_directory) { char script[QUERY_STR_LEN]; char options[QUERY_STR_LEN]; char host_string[QUERY_STR_LEN]; - int r; + int r; - sprintf(options, "--archive --checksum --compress --progress --rsh=ssh"); + sprintf(options, "--archive --checksum --compress --progress --rsh=ssh"); if (force) strcat(options, " --delete"); @@ -1288,24 +1339,26 @@ copy_remote_files(char *host, char *remote_user, char *remote_path, char *local_ if (is_directory) { - strcat(options, " --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid"); - sprintf(script, "rsync %s %s:%s/* %s", - options, host_string, remote_path, local_path); + strcat(options, + " --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid"); + sprintf(script, "rsync %s %s:%s/* %s", + options, host_string, remote_path, local_path); } else { - sprintf(script, "rsync %s %s:%s %s/.", - options, host_string, remote_path, local_path); + sprintf(script, "rsync %s %s:%s %s/.", + options, host_string, remote_path, local_path); } if (verbose) - printf("rsync command line: '%s'\n",script); + printf("rsync command line: '%s'\n",script); r = system(script); - - if (r != 0) - fprintf(stderr, _("Can't rsync from remote file or directory (%s:%s)\n"), - host_string, remote_path); + + if (r != 0) + fprintf(stderr, + _("Can't rsync from remote file or directory (%s:%s)\n"), + host_string, remote_path); return r; } @@ -1327,16 +1380,18 @@ check_parameters_for_action(const int action) * all other parameters are at least useless and could be * confusing so reject them */ - if ((host != NULL) || (masterport != NULL) || (username != NULL) || - (dbname != NULL)) + if ((host != NULL) || (masterport != NULL) || + (username != NULL) || (dbname != NULL)) { fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a MASTER REGISTER command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; - } + } if (dest_dir != NULL) { fprintf(stderr, "\nYou don't need a destination directory for MASTER REGISTER command"); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; } break; @@ -1346,16 +1401,18 @@ check_parameters_for_action(const int action) * we don't need connection parameters to the master * because we can detect the master in repl_nodes */ - if ((host != NULL) || (masterport != NULL) || (username != NULL) || - (dbname != NULL)) + if ((host != NULL) || (masterport != NULL) || + (username != NULL) || (dbname != NULL)) { fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY REGISTER command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; - } + } if (dest_dir != NULL) { fprintf(stderr, "\nYou don't need a destination directory for STANDBY REGISTER command"); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; } break; @@ -1366,16 +1423,18 @@ check_parameters_for_action(const int action) * because we will try to detect the master in repl_nodes * if we can't find it then the promote action will be cancelled */ - if ((host != NULL) || (masterport != NULL) || (username != NULL) || - (dbname != NULL)) + if ((host != NULL) || (masterport != NULL) || + (username != NULL) || (dbname != NULL)) { fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY PROMOTE command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; - } + } if (dest_dir != NULL) { fprintf(stderr, "\nYou don't need a destination directory for STANDBY PROMOTE command"); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; } break; @@ -1386,28 +1445,31 @@ check_parameters_for_action(const int action) * because we will try to detect the master in repl_nodes * if we can't find it then the follow action will be cancelled */ - if ((host != NULL) || (masterport != NULL) || (username != NULL) || - (dbname != NULL)) + if ((host != NULL) || (masterport != NULL) || + (username != NULL) || (dbname != NULL)) { fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY FOLLOW command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; - } + } if (dest_dir != NULL) { fprintf(stderr, "\nYou don't need a destination directory for STANDBY FOLLOW command"); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; } break; case STANDBY_CLONE: /* * To clone a master into a standby we need connection parameters - * repmgr.conf is useless because we don't have a server running + * repmgr.conf is useless because we don't have a server running * in the standby */ if (config_file != NULL) { fprintf(stderr, "\nYou need to use connection parameters to the master when issuing a STANDBY CLONE command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; } break; diff --git a/repmgr.sql b/repmgr.sql index f28e6d8f..42ccfb8f 100644 --- a/repmgr.sql +++ b/repmgr.sql @@ -7,25 +7,25 @@ CREATE SCHEMA repmgr; */ drop table if exists repl_nodes cascade; CREATE TABLE repl_nodes ( - id integer primary key, - cluster text not null, -- Name to identify the cluster - conninfo text not null + id integer primary key, + cluster text not null, -- Name to identify the cluster + conninfo text not null ); ALTER TABLE repl_nodes OWNER TO repmgr; /* - * Keeps monitor info about every node and their relative "position" + * Keeps monitor info about every node and their relative "position" * to primary */ drop table if exists repl_monitor cascade; CREATE TABLE repl_monitor ( primary_node INTEGER NOT NULL, standby_node INTEGER NOT NULL, - last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, - last_wal_primary_location TEXT NOT NULL, + last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, + last_wal_primary_location TEXT NOT NULL, last_wal_standby_location TEXT NOT NULL, - replication_lag BIGINT NOT NULL, - apply_lag BIGINT NOT NULL + replication_lag BIGINT NOT NULL, + apply_lag BIGINT NOT NULL ); ALTER TABLE repl_monitor OWNER TO repmgr; @@ -33,10 +33,10 @@ ALTER TABLE repl_monitor OWNER TO repmgr; /* * This view shows the latest monitor info about every node. * Interesting thing to see: - * replication_lag: in bytes (this is how far the latest xlog record + * replication_lag: in bytes (this is how far the latest xlog record * we have received is from master) * apply_lag: in bytes (this is how far the latest xlog record - * we have applied is from the latest record we + * we have applied is from the latest record we * have received) * time_lag: how many seconds are we from being up-to-date with master */ @@ -45,9 +45,9 @@ CREATE VIEW repl_status AS WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node ORDER BY last_monitor_time desc) FROM repl_monitor) -SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, - last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, - pg_size_pretty(apply_lag) apply_lag, +SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, + last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, + pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag FROM monitor_info a WHERE row_number = 1; diff --git a/repmgrd.c b/repmgrd.c index 42e9fe7c..a5e00ce8 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -4,7 +4,7 @@ * * Replication manager daemon * This module connects to the nodes of a replication cluster and monitors - * how far are they from master + * how far are they from master */ #include @@ -17,11 +17,11 @@ #include "libpq/pqsignal.h" -char myClusterName[MAXLEN]; +char myClusterName[MAXLEN]; /* Local info */ -int myLocalMode = STANDBY_MODE; -int myLocalId = -1; +int myLocalMode = STANDBY_MODE; +int myLocalId = -1; PGconn *myLocalConn; /* Primary info */ @@ -49,23 +49,23 @@ static unsigned long long int walLocationToBytes(char *wal_location); static void handle_sigint(SIGNAL_ARGS); static void setup_cancel_handler(void); -#define CloseConnections() \ - if (PQisBusy(primaryConn) == 1) \ - CancelQuery(); \ - if (myLocalConn != NULL) \ - PQfinish(myLocalConn); \ - if (primaryConn != NULL) \ - PQfinish(primaryConn); +#define CloseConnections() \ + if (PQisBusy(primaryConn) == 1) \ + CancelQuery(); \ + if (myLocalConn != NULL) \ + PQfinish(myLocalConn); \ + if (primaryConn != NULL) \ + PQfinish(primaryConn); /* * Every 3 seconds, insert monitor info */ -#define MonitorCheck() \ - for (;;) \ - { \ - MonitorExecute(); \ - sleep(3); \ - } +#define MonitorCheck() \ + for (;;) \ + { \ + MonitorExecute(); \ + sleep(3); \ + } int @@ -80,7 +80,7 @@ main(int argc, char **argv) int optindex; int c; - char conninfo[MAXLEN]; + char conninfo[MAXLEN]; const char *standby_version = NULL; progname = get_progname(argv[0]); @@ -111,13 +111,14 @@ main(int argc, char **argv) verbose = true; break; default: - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); } } setup_cancel_handler(); - + if (config_file == NULL) { config_file = malloc(5 + sizeof(CONFIG_FILE)); @@ -126,30 +127,31 @@ main(int argc, char **argv) /* * Read the configuration file: repmgr.conf - */ + */ parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) + if (myLocalId == -1) { fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); + "Check the configuration file.\n"); exit(1); } - myLocalConn = establishDBConnection(conninfo, true); + myLocalConn = establishDBConnection(conninfo, true); /* should be v9 or better */ standby_version = pg_version(myLocalConn); if (strcmp(standby_version, "") == 0) { PQfinish(myLocalConn); - fprintf(stderr, _("%s needs standby to be PostgreSQL 9.0 or better\n"), progname); + fprintf(stderr, _("%s needs standby to be PostgreSQL 9.0 or better\n"), + progname); exit(1); } - /* - * Set my server mode, establish a connection to primary + /* + * Set my server mode, establish a connection to primary * and start monitor - */ + */ myLocalMode = is_standby(myLocalConn) ? STANDBY_MODE : PRIMARY_MODE; if (myLocalMode == PRIMARY_MODE) { @@ -160,7 +162,8 @@ main(int argc, char **argv) else { /* I need the id of the primary as well as a connection to it */ - primaryConn = getMasterConnection(myLocalConn, myLocalId, myClusterName, &primaryId); + primaryConn = getMasterConnection(myLocalConn, myLocalId, + myClusterName, &primaryId); if (primaryConn == NULL) exit(1); } @@ -169,13 +172,13 @@ main(int argc, char **argv) checkNodeConfiguration(conninfo); if (myLocalMode == STANDBY_MODE) { - MonitorCheck(); + MonitorCheck(); } - /* close the connection to the database and cleanup */ - CloseConnections(); + /* close the connection to the database and cleanup */ + CloseConnections(); - return 0; + return 0; } @@ -187,7 +190,7 @@ main(int argc, char **argv) static void MonitorExecute(void) { - PGresult *res; + PGresult *res; char monitor_standby_timestamp[MAXLEN]; char last_wal_primary_location[MAXLEN]; char last_wal_standby_received[MAXLEN]; @@ -199,9 +202,9 @@ MonitorExecute(void) int connection_retries; - /* - * Check if the master is still available, if after 5 minutes of retries - * we cannot reconnect, try to get a new master. + /* + * Check if the master is still available, if after 5 minutes of retries + * we cannot reconnect, try to get a new master. */ for (connection_retries = 0; connection_retries < 15; connection_retries++) { @@ -212,7 +215,7 @@ MonitorExecute(void) sleep(20); PQreset(primaryConn); - } + } else { fprintf(stderr, "\n%s: Connection to master has been restored, continue monitoring.\n", progname); @@ -221,11 +224,14 @@ MonitorExecute(void) } if (PQstatus(primaryConn) != CONNECTION_OK) { - fprintf(stderr, "\n%s: We couldn't reconnect to master, checking if ", progname); + fprintf(stderr, "\n%s: We couldn't reconnect to master, checking if ", + progname); fprintf(stderr, "%s: another node has been promoted.\n", progname); - for (connection_retries = 0; connection_retries < 6; connection_retries++) + for (connection_retries = 0; connection_retries < 6; + connection_retries++) { - primaryConn = getMasterConnection(myLocalConn, myLocalId, myClusterName, &primaryId); + primaryConn = getMasterConnection(myLocalConn, myLocalId, + myClusterName, &primaryId); if (PQstatus(primaryConn) == CONNECTION_OK) { /* Connected, we can continue the process so break the loop */ @@ -248,53 +254,53 @@ MonitorExecute(void) /* Check if we still are a standby, we could have been promoted */ if (!is_standby(myLocalConn)) - { - fprintf(stderr, "\n%s: seems like we have been promoted, so exit from monitoring...\n", + { + fprintf(stderr, "\n%s: seems like we have been promoted, so exit from monitoring...\n", progname); CloseConnections(); exit(1); } - /* + /* * first check if there is a command being executed, * and if that is the case, cancel the query so i can - * insert the current record - */ + * insert the current record + */ if (PQisBusy(primaryConn) == 1) CancelQuery(); /* Get local xlog info */ - sprintf(sqlquery, - "SELECT CURRENT_TIMESTAMP, pg_last_xlog_receive_location(), " - "pg_last_xlog_replay_location()"); + sprintf(sqlquery, + "SELECT CURRENT_TIMESTAMP, pg_last_xlog_receive_location(), " + "pg_last_xlog_replay_location()"); - res = PQexec(myLocalConn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "PQexec failed: %s\n", PQerrorMessage(myLocalConn)); - PQclear(res); + res = PQexec(myLocalConn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "PQexec failed: %s\n", PQerrorMessage(myLocalConn)); + PQclear(res); /* if there is any error just let it be and retry in next loop */ - return; - } + return; + } - strcpy(monitor_standby_timestamp, PQgetvalue(res, 0, 0)); - strcpy(last_wal_standby_received , PQgetvalue(res, 0, 1)); - strcpy(last_wal_standby_applied , PQgetvalue(res, 0, 2)); - PQclear(res); + strcpy(monitor_standby_timestamp, PQgetvalue(res, 0, 0)); + strcpy(last_wal_standby_received , PQgetvalue(res, 0, 1)); + strcpy(last_wal_standby_applied , PQgetvalue(res, 0, 2)); + PQclear(res); /* Get primary xlog info */ - sprintf(sqlquery, "SELECT pg_current_xlog_location() "); + sprintf(sqlquery, "SELECT pg_current_xlog_location() "); - res = PQexec(primaryConn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "PQexec failed: %s\n", PQerrorMessage(primaryConn)); - PQclear(res); - return; - } + res = PQexec(primaryConn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "PQexec failed: %s\n", PQerrorMessage(primaryConn)); + PQclear(res); + return; + } - strcpy(last_wal_primary_location, PQgetvalue(res, 0, 0)); - PQclear(res); + strcpy(last_wal_primary_location, PQgetvalue(res, 0, 0)); + PQclear(res); /* Calculate the lag */ lsn_primary = walLocationToBytes(last_wal_primary_location); @@ -305,15 +311,15 @@ MonitorExecute(void) * Build the SQL to execute on primary */ sprintf(sqlquery, - "INSERT INTO repmgr_%s.repl_monitor " - "VALUES(%d, %d, '%s'::timestamp with time zone, " - " '%s', '%s', " - " %lld, %lld)", myClusterName, - primaryId, myLocalId, monitor_standby_timestamp, - last_wal_primary_location, - last_wal_standby_received, - (lsn_primary - lsn_standby_received), - (lsn_standby_received - lsn_standby_applied)); + "INSERT INTO repmgr_%s.repl_monitor " + "VALUES(%d, %d, '%s'::timestamp with time zone, " + " '%s', '%s', " + " %lld, %lld)", myClusterName, + primaryId, myLocalId, monitor_standby_timestamp, + last_wal_primary_location, + last_wal_standby_received, + (lsn_primary - lsn_standby_received), + (lsn_standby_received - lsn_standby_applied)); /* * Execute the query asynchronously, but don't check for a result. We @@ -321,39 +327,41 @@ MonitorExecute(void) */ if (PQsendQuery(primaryConn, sqlquery) == 0) fprintf(stderr, "Query could not be sent to primary. %s\n", - PQerrorMessage(primaryConn)); + PQerrorMessage(primaryConn)); } static void checkClusterConfiguration(void) { - PGresult *res; + PGresult *res; sprintf(sqlquery, "SELECT oid FROM pg_class " - " WHERE oid = 'repmgr_%s.repl_nodes'::regclass", - myClusterName); - res = PQexec(myLocalConn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "PQexec failed: %s\n", PQerrorMessage(myLocalConn)); - PQclear(res); - PQfinish(myLocalConn); - PQfinish(primaryConn); + " WHERE oid = 'repmgr_%s.repl_nodes'::regclass", + myClusterName); + res = PQexec(myLocalConn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "PQexec failed: %s\n", PQerrorMessage(myLocalConn)); + PQclear(res); + PQfinish(myLocalConn); + PQfinish(primaryConn); exit(1); - } + } /* - * If there isn't any results then we have not configured a primary node yet - * in repmgr or the connection string is pointing to the wrong database. + * If there isn't any results then we have not configured a primary node + * yet in repmgr or the connection string is pointing to the wrong + * database. + * * XXX if we are the primary, should we try to create the tables needed? */ if (PQntuples(res) == 0) { - fprintf(stderr, "The replication cluster is not configured\n"); - PQclear(res); - PQfinish(myLocalConn); - PQfinish(primaryConn); + fprintf(stderr, "The replication cluster is not configured\n"); + PQclear(res); + PQfinish(myLocalConn); + PQfinish(primaryConn); exit(1); } PQclear(res); @@ -363,41 +371,40 @@ checkClusterConfiguration(void) static void 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 " - " WHERE id = %d AND cluster = '%s' ", - myClusterName, myLocalId, myClusterName); + " WHERE id = %d AND cluster = '%s' ", + myClusterName, myLocalId, myClusterName); - res = PQexec(myLocalConn, sqlquery); - if (PQresultStatus(res) != PGRES_TUPLES_OK) - { - fprintf(stderr, "PQexec failed: %s\n", PQerrorMessage(myLocalConn)); - PQclear(res); - PQfinish(myLocalConn); - PQfinish(primaryConn); + res = PQexec(myLocalConn, sqlquery); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "PQexec failed: %s\n", PQerrorMessage(myLocalConn)); + PQclear(res); + PQfinish(myLocalConn); + PQfinish(primaryConn); exit(1); - } + } /* * If there isn't any results then we have not configured this node yet - * in repmgr, if that is the case we will insert the node to the cluster + * in repmgr, if that is the case we will insert the node to the cluster */ if (PQntuples(res) == 0) { - PQclear(res); + PQclear(res); + /* Adding the node */ sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " - "VALUES (%d, '%s', '%s')", - myClusterName, myLocalId, myClusterName, conninfo); + "VALUES (%d, '%s', '%s')", + myClusterName, myLocalId, myClusterName, conninfo); - if (!PQexec(primaryConn, sqlquery)) + if (!PQexec(primaryConn, sqlquery)) { fprintf(stderr, "Cannot insert node details, %s\n", - PQerrorMessage(primaryConn)); + PQerrorMessage(primaryConn)); PQfinish(myLocalConn); PQfinish(primaryConn); exit(1); @@ -407,33 +414,33 @@ checkNodeConfiguration(char *conninfo) } -static unsigned long long int +static unsigned long long int walLocationToBytes(char *wal_location) { - unsigned int xlogid; - unsigned int xrecoff; + unsigned int xlogid; + unsigned int xrecoff; - if (sscanf(wal_location, "%X/%X", &xlogid, &xrecoff) != 2) - { - fprintf(stderr, "wrong log location format: %s\n", wal_location); - return 0; - } - return ((xlogid * 16 * 1024 * 1024 * 255) + xrecoff); + if (sscanf(wal_location, "%X/%X", &xlogid, &xrecoff) != 2) + { + fprintf(stderr, "wrong log location format: %s\n", wal_location); + return 0; + } + return ((xlogid * 16 * 1024 * 1024 * 255) + xrecoff); } -static void +static void help(const char *progname) { - printf(_("\n%s: Replicator manager daemon \n"), progname); - printf(_("Usage:\n")); - printf(_(" %s [OPTIONS]\n"), progname); - printf(_("\nOptions:\n")); - printf(_(" --help show this help, then exit\n")); - printf(_(" --version output version information, then exit\n")); - printf(_(" --verbose output verbose activity information\n")); - printf(_(" -f, --config_file=PATH database to connect to\n")); - printf(_("\n%s monitors a cluster of servers.\n"), progname); + printf(_("\n%s: Replicator manager daemon \n"), progname); + printf(_("Usage:\n")); + printf(_(" %s [OPTIONS]\n"), progname); + printf(_("\nOptions:\n")); + printf(_(" --help show this help, then exit\n")); + printf(_(" --version output version information, then exit\n")); + printf(_(" --verbose output verbose activity information\n")); + printf(_(" -f, --config_file=PATH database to connect to\n")); + printf(_("\n%s monitors a cluster of servers.\n"), progname); } @@ -442,13 +449,13 @@ help(const char *progname) static void handle_sigint(SIGNAL_ARGS) { - CloseConnections(); + CloseConnections(); } static void setup_cancel_handler(void) { - pqsignal(SIGINT, handle_sigint); + pqsignal(SIGINT, handle_sigint); } #endif @@ -456,13 +463,13 @@ setup_cancel_handler(void) static void CancelQuery(void) { - char errbuf[256]; - PGcancel *pgcancel; + char errbuf[256]; + PGcancel *pgcancel; - pgcancel = PQgetCancel(primaryConn); + pgcancel = PQgetCancel(primaryConn); - if (!pgcancel || PQcancel(pgcancel, errbuf, 256) == 0) - fprintf(stderr, "Can't stop current query: %s", errbuf); + if (!pgcancel || PQcancel(pgcancel, errbuf, 256) == 0) + fprintf(stderr, "Can't stop current query: %s", errbuf); - PQfreeCancel(pgcancel); + PQfreeCancel(pgcancel); } From 778303bb6eaad1e125ad2dd3385b6cd7bf255573 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Tue, 7 Dec 2010 21:30:20 -0800 Subject: [PATCH 02/34] Split up install/uninstall actions more like a standard contrib Signed-off-by: Dan Farina Signed-off-by: Peter van Hardenberg --- repmgr.sql | 10 +++++++--- uninstall_repmgr.sql | 13 +++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 uninstall_repmgr.sql diff --git a/repmgr.sql b/repmgr.sql index 42ccfb8f..4a300816 100644 --- a/repmgr.sql +++ b/repmgr.sql @@ -1,3 +1,10 @@ +/* + * repmgr.sql + * + * Copyright (c) Heroku, 2010 + * + */ + CREATE USER repmgr; CREATE SCHEMA repmgr; @@ -5,7 +12,6 @@ CREATE SCHEMA repmgr; * The table repl_nodes keeps information about all machines in * a cluster */ -drop table if exists repl_nodes cascade; CREATE TABLE repl_nodes ( id integer primary key, cluster text not null, -- Name to identify the cluster @@ -17,7 +23,6 @@ ALTER TABLE repl_nodes OWNER TO repmgr; * Keeps monitor info about every node and their relative "position" * to primary */ -drop table if exists repl_monitor cascade; CREATE TABLE repl_monitor ( primary_node INTEGER NOT NULL, standby_node INTEGER NOT NULL, @@ -40,7 +45,6 @@ ALTER TABLE repl_monitor OWNER TO repmgr; * have received) * time_lag: how many seconds are we from being up-to-date with master */ -drop view if exists repl_status; CREATE VIEW repl_status AS WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node ORDER BY last_monitor_time desc) diff --git a/uninstall_repmgr.sql b/uninstall_repmgr.sql new file mode 100644 index 00000000..8cb1b4de --- /dev/null +++ b/uninstall_repmgr.sql @@ -0,0 +1,13 @@ +/* + * uninstall_repmgr.sql + * + * Copyright (c) Heroku, 2010 + * + */ + +DROP TABLE IF EXISTS repl_nodes; +DROP TABLE IF EXISTS repl_monitor; +DROP VIEW IF EXISTS repl_status; + +DROP SCHEMA repmgr; +DROP USER repmgr; From 846c0b92e883879e5c44051a7d2fc78a0ffa04d6 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Tue, 7 Dec 2010 21:30:44 -0800 Subject: [PATCH 03/34] Install install/uninstall SQL also. Signed-off-by: Dan Farina Signed-off-by: Peter van Hardenberg --- Makefile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Makefile b/Makefile index 655467ac..9c5c9758 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ # # Makefile +# # Copyright (c) 2ndQuadrant, 2010 +# Copyright (c) Heroku, 2010 repmgrd_OBJS = dbutils.o config.o repmgrd.o repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o @@ -26,10 +28,19 @@ include $(top_builddir)/src/Makefile.global include $(top_srcdir)/contrib/contrib-global.mk endif +# XXX: Try to use PROGRAM construct (see pgxs.mk) someday. Right now +# is overriding pgxs install. install: $(INSTALL_PROGRAM) repmgrd$(X) '$(DESTDIR)$(bindir)' $(INSTALL_PROGRAM) repmgr$(X) '$(DESTDIR)$(bindir)' +ifneq (,$(DATA)$(DATA_built)) + @for file in $(addprefix $(srcdir)/, $(DATA)) $(DATA_built); do \ + echo "$(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/$(datamoduledir)'"; \ + $(INSTALL_DATA) $$file '$(DESTDIR)$(datadir)/$(datamoduledir)'; \ + done +endif + clean: rm -f *.o rm -f repmgrd From 916c0492fbb67aa682f7e63bb2150b77948d2ad7 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Tue, 7 Dec 2010 21:31:49 -0800 Subject: [PATCH 04/34] 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 Signed-off-by: Peter van Hardenberg --- Makefile | 6 ++-- check_dir.c | 12 +++++-- config.c | 4 +++ dbutils.c | 28 ++++++++++------- repmgr.c | 90 ++++++++++++++++++++++++++++------------------------- repmgr.h | 5 +-- repmgrd.c | 21 +++++++------ strutil.c | 72 ++++++++++++++++++++++++++++++++++++++++++ strutil.h | 19 +++++++++++ 9 files changed, 187 insertions(+), 70 deletions(-) create mode 100644 strutil.c create mode 100644 strutil.h diff --git a/Makefile b/Makefile index 9c5c9758..dccbf2cf 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,10 @@ # Copyright (c) 2ndQuadrant, 2010 # Copyright (c) Heroku, 2010 -repmgrd_OBJS = dbutils.o config.o repmgrd.o -repmgr_OBJS = dbutils.o check_dir.o config.o repmgr.o +repmgrd_OBJS = dbutils.o config.o repmgrd.o strutil.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_LIBS = $(libpq_pgport) diff --git a/check_dir.c b/check_dir.c index 7296261d..e0220b7b 100644 --- a/check_dir.c +++ b/check_dir.c @@ -1,6 +1,8 @@ /* * check_dir.c + * * Copyright (c) 2ndQuadrant, 2010 + * Copyright (c) Heroku, 2010 * * Directories management functions */ @@ -12,9 +14,12 @@ #include #include +/* NB: postgres_fe must be included BEFORE check_dir */ #include "postgres_fe.h" #include "check_dir.h" +#include "strutil.h" + static int mkdir_p(char *path, mode_t omode); @@ -207,10 +212,11 @@ mkdir_p(char *path, mode_t omode) bool is_pg_dir(char *dir) { - char path[8192]; - struct stat sb; + const size_t buf_sz = 8192; + 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; } diff --git a/config.c b/config.c index 4c4ecdb6..6ae49e5b 100644 --- a/config.c +++ b/config.c @@ -1,12 +1,16 @@ /* * config.c + * * Copyright (c) 2ndQuadrant, 2010 + * Copyright (c) Heroku, 2010 * * Functions to parse the config file */ #include "repmgr.h" +#include "strutil.h" + void parse_config(const char *config_file, char *cluster_name, int *node, char *conninfo) diff --git a/dbutils.c b/dbutils.c index bec62d66..e3f5577f 100644 --- a/dbutils.c +++ b/dbutils.c @@ -7,6 +7,7 @@ */ #include "repmgr.h" +#include "strutil.h" PGconn * establishDBConnection(const char *conninfo, const bool exit_on_error) @@ -66,11 +67,13 @@ is_standby(PGconn *conn) char * pg_version(PGconn *conn) { - PGresult *res; - char *major_version; + PGresult *res; - int major_version1; - char *major_version2; + const size_t major_version_sz = 10; + char *major_version; + + int major_version1; + char *major_version2; res = PQexec(conn, "WITH pg_version(ver) AS " @@ -90,12 +93,13 @@ pg_version(PGconn *conn) major_version2 = PQgetvalue(res, 0, 1); PQclear(res); - major_version = malloc(10); + major_version = malloc(major_version_sz); if (major_version1 >= 9) { /* 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 strcpy(major_version, ""); @@ -109,9 +113,9 @@ guc_setted(PGconn *conn, const char *parameter, const char *op, const char *value) { 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'", parameter, op, value); @@ -139,9 +143,9 @@ get_cluster_size(PGconn *conn) { PGresult *res; 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) " " FROM pg_database "); @@ -169,12 +173,12 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, PGconn *master_conn = NULL; PGresult *res1; PGresult *res2; - char sqlquery[8192]; + char sqlquery[QUERY_STR_LEN]; char master_conninfo[8192]; int i; /* 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", cluster, cluster, id); diff --git a/repmgr.c b/repmgr.c index 950c6761..61d1e85f 100644 --- a/repmgr.c +++ b/repmgr.c @@ -1,6 +1,8 @@ /* * repmgr.c + * * Copyright (c) 2ndQuadrant, 2010 + * Copyright (c) Heroku, 2010 * * Command interpreter for the repmgr * This module is a command-line utility to easily setup a cluster of @@ -19,6 +21,7 @@ #include #include "check_dir.h" +#include "strutil.h" #define RECOVERY_FILE "recovery.conf" #define RECOVERY_DONE_FILE "recovery.done" @@ -30,7 +33,6 @@ #define STANDBY_PROMOTE 4 #define STANDBY_FOLLOW 5 -#define QUERY_STR_LEN 8192 static void help(const char *progname); static bool create_recovery_file(const char *data_dir); @@ -227,8 +229,10 @@ main(int argc, char **argv) if (config_file == NULL) { - config_file = malloc(5 + sizeof(CONFIG_FILE)); - sprintf(config_file, "./%s", CONFIG_FILE); + const int buf_sz = 3 + sizeof(CONFIG_FILE); + + config_file = malloc(buf_sz); + xsnprintf(config_file, buf_sz, "./%s", CONFIG_FILE); } if (wal_keep_segments == NULL) @@ -329,7 +333,8 @@ do_master_register(void) } /* 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); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -357,7 +362,7 @@ do_master_register(void) if (!schema_exists) { /* ok, create the schema */ - sprintf(sqlquery, "CREATE SCHEMA repmgr_%s", myClusterName); + sqlquery_snprintf(sqlquery, "CREATE SCHEMA repmgr_%s", myClusterName); if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot create the schema repmgr_%s: %s\n", @@ -367,7 +372,7 @@ do_master_register(void) } /* ... the tables */ - sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( " + sqlquery_snprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( " " id integer primary key, " " cluster text not null, " " conninfo text not null)", myClusterName); @@ -380,7 +385,7 @@ do_master_register(void) return; } - sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_monitor ( " + sqlquery_snprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_monitor ( " " primary_node INTEGER NOT NULL, " " standby_node INTEGER NOT NULL, " " last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, " @@ -399,7 +404,7 @@ do_master_register(void) } /* 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 " " ORDER BY last_monitor_time desc) " " FROM repmgr_%s.repl_monitor) " @@ -435,7 +440,7 @@ do_master_register(void) /* Now register the master */ if (force) { - sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " + sqlquery_snprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " " WHERE id = %d", 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')", myClusterName, myLocalId, myClusterName, conninfo); @@ -514,7 +519,7 @@ do_standby_register(void) } /* 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); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -566,7 +571,7 @@ do_standby_register(void) /* Now register the standby */ if (force) { - sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " + sqlquery_snprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " " WHERE id = %d", 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')", 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)); /* 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); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -819,7 +824,7 @@ do_standby_clone(void) fprintf(stderr, "Starting backup...\n"); /* 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 " " WHERE name IN ('data_directory', 'config_file', 'hba_file', 'ident_file')"); 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 * 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); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -876,9 +881,9 @@ do_standby_clone(void) */ /* need to create the global sub directory */ - sprintf(master_control_file, "%s/global/pg_control", - master_data_directory); - sprintf(local_control_file, "%s/global", dest_dir); + maxlen_snprintf(master_control_file, "%s/global/pg_control", + master_data_directory); + maxlen_snprintf(local_control_file, "%s/global", dest_dir); if (!create_directory(local_control_file)) { 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 * 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); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -944,7 +949,7 @@ stop_backup: 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); 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 * 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)) { 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; PGresult *res; char sqlquery[QUERY_STR_LEN]; - char script[QUERY_STR_LEN]; + char script[MAXLEN]; char myClusterName[MAXLEN]; int myLocalId = -1; @@ -1056,7 +1061,7 @@ do_standby_promote(void) printf(_("\n%s: Promoting standby...\n"), progname); /* 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'"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -1071,12 +1076,12 @@ do_standby_promote(void) PQclear(res); PQfinish(conn); - sprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE); - sprintf(recovery_done_path, "%s/%s", data_dir, RECOVERY_DONE_FILE); + maxlen_snprintf(recovery_file_path, "%s/%s", data_dir, RECOVERY_FILE); + maxlen_snprintf(recovery_done_path, "%s/%s", data_dir, RECOVERY_DONE_FILE); rename(recovery_file_path, recovery_done_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); if (r != 0) { @@ -1108,7 +1113,7 @@ do_standby_follow(void) PGconn *conn; PGresult *res; char sqlquery[QUERY_STR_LEN]; - char script[QUERY_STR_LEN]; + char script[MAXLEN]; char myClusterName[MAXLEN]; int myLocalId = -1; @@ -1206,7 +1211,7 @@ do_standby_follow(void) printf(_("\n%s: Changing standby's master...\n"), progname); /* Get the data directory full path */ - sprintf(sqlquery, "SELECT setting " + sqlquery_snprintf(sqlquery, "SELECT setting " " FROM pg_settings WHERE name = 'data_directory'"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -1227,7 +1232,7 @@ do_standby_follow(void) /* Finally, restart the service */ /* 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); if (r != 0) { @@ -1282,7 +1287,7 @@ create_recovery_file(const char *data_dir) char recovery_file_path[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"); if (recovery_file == NULL) @@ -1291,7 +1296,7 @@ create_recovery_file(const char *data_dir) return false; } - sprintf(line, "standby_mode = 'on'\n"); + maxlen_snprintf(line, "standby_mode = 'on'\n"); if (fputs(line, recovery_file) == EOF) { 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; } - 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)); if (fputs(line, recovery_file) == EOF) { @@ -1319,35 +1324,36 @@ static int copy_remote_files(char *host, char *remote_user, char *remote_path, char *local_path, bool is_directory) { - char script[QUERY_STR_LEN]; - char options[QUERY_STR_LEN]; - char host_string[QUERY_STR_LEN]; + char script[MAXLEN]; + char options[MAXLEN]; + char host_string[MAXLEN]; int r; - sprintf(options, "--archive --checksum --compress --progress --rsh=ssh"); + maxlen_snprintf(options, + "--archive --checksum --compress --progress --rsh=ssh"); if (force) strcat(options, " --delete"); if (remote_user == NULL) { - sprintf(host_string,"%s",host); + maxlen_snprintf(host_string, "%s", host); } else { - sprintf(host_string,"%s@%s",remote_user,host); + maxlen_snprintf(host_string,"%s@%s",remote_user,host); } if (is_directory) { strcat(options, " --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); } else { - sprintf(script, "rsync %s %s:%s %s/.", - options, host_string, remote_path, local_path); + maxlen_snprintf(script, "rsync %s %s:%s %s/.", + options, host_string, remote_path, local_path); } if (verbose) diff --git a/repmgr.h b/repmgr.h index 4768f966..93e7ed49 100644 --- a/repmgr.h +++ b/repmgr.h @@ -1,6 +1,8 @@ /* - * dbutils.h + * repmgr.h + * * Copyright (c) 2ndQuadrant, 2010 + * Copyright (c) Heroku, 2010 * */ @@ -18,7 +20,6 @@ #define PRIMARY_MODE 0 #define STANDBY_MODE 1 -#define MAXLEN 80 #define CONFIG_FILE "repmgr.conf" #endif diff --git a/repmgrd.c b/repmgrd.c index a5e00ce8..d4f41131 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -14,6 +14,7 @@ #include #include "repmgr.h" +#include "strutil.h" #include "libpq/pqsignal.h" @@ -29,7 +30,7 @@ int primaryId; char primaryConninfo[MAXLEN]; PGconn *primaryConn; -char sqlquery[8192]; +char sqlquery[QUERY_STR_LEN]; const char *progname; @@ -121,8 +122,10 @@ main(int argc, char **argv) if (config_file == NULL) { - config_file = malloc(5 + sizeof(CONFIG_FILE)); - sprintf(config_file, "./%s", CONFIG_FILE); + const size_t buf_sz = 3 + sizeof(CONFIG_FILE); + + config_file = malloc(buf_sz); + xsnprintf(config_file, buf_sz, "./%s", CONFIG_FILE); } /* @@ -270,7 +273,7 @@ MonitorExecute(void) CancelQuery(); /* Get local xlog info */ - sprintf(sqlquery, + sqlquery_snprintf(sqlquery, "SELECT CURRENT_TIMESTAMP, pg_last_xlog_receive_location(), " "pg_last_xlog_replay_location()"); @@ -289,7 +292,7 @@ MonitorExecute(void) PQclear(res); /* Get primary xlog info */ - sprintf(sqlquery, "SELECT pg_current_xlog_location() "); + sqlquery_snprintf(sqlquery, "SELECT pg_current_xlog_location() "); res = PQexec(primaryConn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -310,7 +313,7 @@ MonitorExecute(void) /* * Build the SQL to execute on primary */ - sprintf(sqlquery, + sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_monitor " "VALUES(%d, %d, '%s'::timestamp with time zone, " " '%s', '%s', " @@ -336,7 +339,7 @@ checkClusterConfiguration(void) { PGresult *res; - sprintf(sqlquery, "SELECT oid FROM pg_class " + sqlquery_snprintf(sqlquery, "SELECT oid FROM pg_class " " WHERE oid = 'repmgr_%s.repl_nodes'::regclass", myClusterName); res = PQexec(myLocalConn, sqlquery); @@ -374,7 +377,7 @@ checkNodeConfiguration(char *conninfo) PGresult *res; /* 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' ", myClusterName, myLocalId, myClusterName); @@ -397,7 +400,7 @@ checkNodeConfiguration(char *conninfo) PQclear(res); /* Adding the node */ - sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " + sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " "VALUES (%d, '%s', '%s')", myClusterName, myLocalId, myClusterName, conninfo); diff --git a/strutil.c b/strutil.c new file mode 100644 index 00000000..6286c31e --- /dev/null +++ b/strutil.c @@ -0,0 +1,72 @@ +/* + * strutil.c + * + * Copyright (c) Heroku, 2010 + * + */ + +#include +#include +#include + +#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; +} diff --git a/strutil.h b/strutil.h new file mode 100644 index 00000000..c2f5d55c --- /dev/null +++ b/strutil.h @@ -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_ */ From 84b69b3bd4b879330284eca179a8d1ca8fdeb943 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Tue, 7 Dec 2010 21:37:56 -0800 Subject: [PATCH 05/34] Whitespace to adjust for longer snprintf identifier This is done in a separate patch to try and reduce the sound and fury of the patch that actually did the conversion from sprintf to snprintf-alikes. Signed-off-by: Dan Farina Signed-off-by: Peter van Hardenberg --- config.c | 2 +- dbutils.c | 15 +++++---- repmgr.c | 97 ++++++++++++++++++++++++++++++++----------------------- repmgrd.c | 39 +++++++++++----------- 4 files changed, 85 insertions(+), 68 deletions(-) diff --git a/config.c b/config.c index 6ae49e5b..2aac8c16 100644 --- a/config.c +++ b/config.c @@ -43,7 +43,7 @@ parse_config(const char *config_file, char *cluster_name, int *node, strncpy (conninfo, value, MAXLEN); else printf("WARNING: %s/%s: Unknown name/value pair!\n", - name, value); + name, value); } /* Close file */ diff --git a/dbutils.c b/dbutils.c index e3f5577f..9a771dfd 100644 --- a/dbutils.c +++ b/dbutils.c @@ -116,8 +116,8 @@ guc_setted(PGconn *conn, const char *parameter, const char *op, char sqlquery[QUERY_STR_LEN]; sqlquery_snprintf(sqlquery, "SELECT true FROM pg_settings " - " WHERE name = '%s' AND setting %s '%s'", - parameter, op, value); + " WHERE name = '%s' AND setting %s '%s'", + parameter, op, value); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -145,9 +145,10 @@ get_cluster_size(PGconn *conn) const char *size; char sqlquery[QUERY_STR_LEN]; - sqlquery_snprintf(sqlquery, - "SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) " - " FROM pg_database "); + sqlquery_snprintf( + sqlquery, + "SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) " + " FROM pg_database "); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -179,8 +180,8 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, /* find all nodes belonging to this cluster */ sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes " - " WHERE cluster = '%s' and id <> %d", - cluster, cluster, id); + " WHERE cluster = '%s' and id <> %d", + cluster, cluster, id); res1 = PQexec(standby_conn, sqlquery); if (PQresultStatus(res1) != PGRES_TUPLES_OK) diff --git a/repmgr.c b/repmgr.c index 61d1e85f..d9d96006 100644 --- a/repmgr.c +++ b/repmgr.c @@ -335,7 +335,7 @@ do_master_register(void) /* Check if there is a schema for this cluster */ sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", - myClusterName); + myClusterName); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -373,9 +373,9 @@ do_master_register(void) /* ... the tables */ sqlquery_snprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( " - " id integer primary key, " - " cluster text not null, " - " conninfo text not null)", myClusterName); + " id integer primary key, " + " cluster text not null, " + " conninfo text not null)", myClusterName); if (!PQexec(conn, sqlquery)) { fprintf(stderr, @@ -386,14 +386,14 @@ do_master_register(void) } sqlquery_snprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_monitor ( " - " primary_node INTEGER NOT NULL, " - " standby_node INTEGER NOT NULL, " - " last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, " - " last_wal_primary_location TEXT NOT NULL, " - " last_wal_standby_location TEXT NOT NULL, " - " replication_lag BIGINT NOT NULL, " - " apply_lag BIGINT NOT NULL) ", - myClusterName); + " primary_node INTEGER NOT NULL, " + " standby_node INTEGER NOT NULL, " + " last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, " + " last_wal_primary_location TEXT NOT NULL, " + " last_wal_standby_location TEXT NOT NULL, " + " replication_lag BIGINT NOT NULL, " + " apply_lag BIGINT NOT NULL) ", + myClusterName); if (!PQexec(conn, sqlquery)) { fprintf(stderr, @@ -405,14 +405,14 @@ do_master_register(void) /* and the view */ sqlquery_snprintf(sqlquery, "CREATE VIEW repmgr_%s.repl_status AS " - " WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node " - " ORDER BY last_monitor_time desc) " - " FROM repmgr_%s.repl_monitor) " - " SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, " - " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " - " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " - " FROM monitor_info a " - " WHERE row_number = 1", myClusterName, myClusterName); + " WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node " + " ORDER BY last_monitor_time desc) " + " FROM repmgr_%s.repl_monitor) " + " SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, " + " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " + " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " + " FROM monitor_info a " + " WHERE row_number = 1", myClusterName, myClusterName); if (!PQexec(conn, sqlquery)) { fprintf(stderr, @@ -441,8 +441,8 @@ do_master_register(void) if (force) { sqlquery_snprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " - " WHERE id = %d", - myClusterName, myLocalId); + " WHERE id = %d", + myClusterName, myLocalId); if (!PQexec(conn, sqlquery)) { @@ -454,8 +454,8 @@ do_master_register(void) } sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " - "VALUES (%d, '%s', '%s')", - myClusterName, myLocalId, myClusterName, conninfo); + "VALUES (%d, '%s', '%s')", + myClusterName, myLocalId, myClusterName, conninfo); if (!PQexec(conn, sqlquery)) { @@ -519,8 +519,9 @@ do_standby_register(void) } /* Check if there is a schema for this cluster */ - sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", - myClusterName); + sqlquery_snprintf(sqlquery, + "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", + myClusterName); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -572,8 +573,8 @@ do_standby_register(void) if (force) { sqlquery_snprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " - " WHERE id = %d", - myClusterName, myLocalId); + " WHERE id = %d", + myClusterName, myLocalId); if (!PQexec(master_conn, sqlquery)) { @@ -586,8 +587,8 @@ do_standby_register(void) } sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " - "VALUES (%d, '%s', '%s')", - myClusterName, myLocalId, myClusterName, conninfo); + "VALUES (%d, '%s', '%s')", + myClusterName, myLocalId, myClusterName, conninfo); if (!PQexec(master_conn, sqlquery)) { @@ -748,8 +749,13 @@ do_standby_clone(void) if (verbose) 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 */ - sqlquery_snprintf(sqlquery, "select spclocation from pg_tablespace where spcname not in ('pg_default', 'pg_global')"); + /* + * Check if the tablespace locations exists and that we can write to them. + */ + sqlquery_snprintf(sqlquery, + "SELECT spclocation " + " FROM pg_tablespace " + "WHERE spcname NOT IN ('pg_default', 'pg_global')"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -824,9 +830,12 @@ do_standby_clone(void) fprintf(stderr, "Starting backup...\n"); /* Get the data directory full path and the configuration files location */ - sqlquery_snprintf(sqlquery, "SELECT name, setting " - " FROM pg_settings " - " WHERE name IN ('data_directory', 'config_file', 'hba_file', 'ident_file')"); + sqlquery_snprintf( + sqlquery, + "SELECT name, setting " + " FROM pg_settings " + " WHERE name IN ('data_directory', 'config_file', 'hba_file', " + " 'ident_file')"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -854,7 +863,10 @@ do_standby_clone(void) * 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 */ - sqlquery_snprintf(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); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -906,7 +918,10 @@ do_standby_clone(void) * find and appropiate rsync option but besides we could someday make all * these rsync happen concurrently */ - sqlquery_snprintf(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); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -1062,7 +1077,7 @@ do_standby_promote(void) /* Get the data directory full path and the last subdirectory */ sqlquery_snprintf(sqlquery, "SELECT setting " - " FROM pg_settings WHERE name = 'data_directory'"); + " FROM pg_settings WHERE name = 'data_directory'"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -1212,7 +1227,7 @@ do_standby_follow(void) /* Get the data directory full path */ sqlquery_snprintf(sqlquery, "SELECT setting " - " FROM pg_settings WHERE name = 'data_directory'"); + " FROM pg_settings WHERE name = 'data_directory'"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -1305,7 +1320,7 @@ create_recovery_file(const char *data_dir) } 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) { fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n"); @@ -1348,7 +1363,7 @@ copy_remote_files(char *host, char *remote_user, char *remote_path, strcat(options, " --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid"); maxlen_snprintf(script, "rsync %s %s:%s/* %s", - options, host_string, remote_path, local_path); + options, host_string, remote_path, local_path); } else { diff --git a/repmgrd.c b/repmgrd.c index d4f41131..03e3d78b 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -61,7 +61,7 @@ static void setup_cancel_handler(void); /* * Every 3 seconds, insert monitor info */ -#define MonitorCheck() \ +#define MonitorCheck() \ for (;;) \ { \ MonitorExecute(); \ @@ -273,9 +273,10 @@ MonitorExecute(void) CancelQuery(); /* Get local xlog info */ - sqlquery_snprintf(sqlquery, - "SELECT CURRENT_TIMESTAMP, pg_last_xlog_receive_location(), " - "pg_last_xlog_replay_location()"); + sqlquery_snprintf( + sqlquery, + "SELECT CURRENT_TIMESTAMP, pg_last_xlog_receive_location(), " + "pg_last_xlog_replay_location()"); res = PQexec(myLocalConn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -314,15 +315,15 @@ MonitorExecute(void) * Build the SQL to execute on primary */ sqlquery_snprintf(sqlquery, - "INSERT INTO repmgr_%s.repl_monitor " - "VALUES(%d, %d, '%s'::timestamp with time zone, " - " '%s', '%s', " - " %lld, %lld)", myClusterName, - primaryId, myLocalId, monitor_standby_timestamp, - last_wal_primary_location, - last_wal_standby_received, - (lsn_primary - lsn_standby_received), - (lsn_standby_received - lsn_standby_applied)); + "INSERT INTO repmgr_%s.repl_monitor " + "VALUES(%d, %d, '%s'::timestamp with time zone, " + " '%s', '%s', " + " %lld, %lld)", myClusterName, + primaryId, myLocalId, monitor_standby_timestamp, + last_wal_primary_location, + last_wal_standby_received, + (lsn_primary - lsn_standby_received), + (lsn_standby_received - lsn_standby_applied)); /* * Execute the query asynchronously, but don't check for a result. We @@ -340,8 +341,8 @@ checkClusterConfiguration(void) PGresult *res; sqlquery_snprintf(sqlquery, "SELECT oid FROM pg_class " - " WHERE oid = 'repmgr_%s.repl_nodes'::regclass", - myClusterName); + " WHERE oid = 'repmgr_%s.repl_nodes'::regclass", + myClusterName); res = PQexec(myLocalConn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -378,8 +379,8 @@ checkNodeConfiguration(char *conninfo) /* Check if we have my node information in repl_nodes */ sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes " - " WHERE id = %d AND cluster = '%s' ", - myClusterName, myLocalId, myClusterName); + " WHERE id = %d AND cluster = '%s' ", + myClusterName, myLocalId, myClusterName); res = PQexec(myLocalConn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -401,8 +402,8 @@ checkNodeConfiguration(char *conninfo) /* Adding the node */ sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " - "VALUES (%d, '%s', '%s')", - myClusterName, myLocalId, myClusterName, conninfo); + "VALUES (%d, '%s', '%s')", + myClusterName, myLocalId, myClusterName, conninfo); if (!PQexec(primaryConn, sqlquery)) { From 3f2094a242153d804f32addd1f3ae50db76cdc77 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Fri, 10 Dec 2010 12:47:09 -0800 Subject: [PATCH 06/34] Initialize connection pointers to NULL This makes some bugs easier to find. Signed-off-by: Dan Farina Signed-off-by: Peter van Hardenberg --- repmgrd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/repmgrd.c b/repmgrd.c index 03e3d78b..c82ddd73 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -1,6 +1,8 @@ /* * repmgrd.c + * * Copyright (c) 2ndQuadrant, 2010 + * Copyright (c) Heroku, 2010 * * Replication manager daemon * This module connects to the nodes of a replication cluster and monitors @@ -23,12 +25,12 @@ char myClusterName[MAXLEN]; /* Local info */ int myLocalMode = STANDBY_MODE; int myLocalId = -1; -PGconn *myLocalConn; +PGconn *myLocalConn = NULL; /* Primary info */ int primaryId; char primaryConninfo[MAXLEN]; -PGconn *primaryConn; +PGconn *primaryConn = NULL; char sqlquery[QUERY_STR_LEN]; From 6cea339697bde657e0e733dcb69f7c3d1b079e8e Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Fri, 10 Dec 2010 12:50:52 -0800 Subject: [PATCH 07/34] Fix a use-after-free A result is being cleared while there are still pointers that refer to datums in it. Signed-off-by: Dan Farina Signed-off-by: Peter van Hardenberg --- dbutils.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dbutils.c b/dbutils.c index 9a771dfd..ebe8373e 100644 --- a/dbutils.c +++ b/dbutils.c @@ -1,6 +1,8 @@ /* * dbutils.c + * * Copyright (c) 2ndQuadrant, 2010 + * Copyright (c) Heroku, 2010 * * Database connection/management functions * @@ -91,7 +93,6 @@ pg_version(PGconn *conn) major_version1 = atoi(PQgetvalue(res, 0, 0)); major_version2 = PQgetvalue(res, 0, 1); - PQclear(res); major_version = malloc(major_version_sz); @@ -104,6 +105,8 @@ pg_version(PGconn *conn) else strcpy(major_version, ""); + PQclear(res); + return major_version; } From 309bb92d95e9aac917bcd9d2ef28e5964666eb94 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Fri, 10 Dec 2010 12:51:42 -0800 Subject: [PATCH 08/34] Prevent a double-free This can occur because prior to this, there is a code path that looks like this: primaryConn = myLocalConn CloseConnections will subsequently try to free both with PQFinish. I'm not sure if this is the right fix -- it's more of hack -- without more information about design intention. One reasonable alternative would be to have CloseConnections perform this check itself. As-is I am pretty sure that this fix leaves a signal-race (when CloseConnections is called, without the check, in the interrupt handler) unfixed. Signed-off-by: Dan Farina Signed-off-by: Peter van Hardenberg --- repmgrd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/repmgrd.c b/repmgrd.c index c82ddd73..3798171c 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -180,6 +180,10 @@ main(int argc, char **argv) MonitorCheck(); } + /* Prevent a double-free */ + if (primaryConn == myLocalConn) + myLocalConn = NULL; + /* close the connection to the database and cleanup */ CloseConnections(); From fc13d50e3797e3f37bab1909f3f3fb5bbea76024 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Fri, 10 Dec 2010 12:55:30 -0800 Subject: [PATCH 09/34] Canonicalize whitespace Signed-off-by: Dan Farina Signed-off-by: Peter van Hardenberg --- config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.c b/config.c index 2aac8c16..41e4bffa 100644 --- a/config.c +++ b/config.c @@ -36,11 +36,11 @@ parse_config(const char *config_file, char *cluster_name, int *node, /* Copy into correct entry in parameters struct */ if (strcmp(name, "cluster") == 0) - strncpy (cluster_name, value, MAXLEN); + strncpy(cluster_name, value, MAXLEN); else if (strcmp(name, "node") == 0) *node = atoi(value); else if (strcmp(name, "conninfo") == 0) - strncpy (conninfo, value, MAXLEN); + strncpy(conninfo, value, MAXLEN); else printf("WARNING: %s/%s: Unknown name/value pair!\n", name, value); From ec73a07e2f654d653ae7b2cd17e722ce32cf0e78 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Fri, 10 Dec 2010 12:55:45 -0800 Subject: [PATCH 10/34] Make various buffers larger MAXLEN definitely needed to be bigger to properly format fairly common connection strings. In addition, the reliance on xsnprintf helps detect cases where even this buffer is not long enough. the buffer in parse_config has been made bigger in a bit of sloppy programming, but what really needs to happen is reporting when a line cannot be properly parsed/is too big for the buffer. That is just a kludge. Signed-off-by: Dan Farina Signed-off-by: Peter van Hardenberg --- config.c | 2 +- strutil.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.c b/config.c index 41e4bffa..1a4b5b07 100644 --- a/config.c +++ b/config.c @@ -15,7 +15,7 @@ void parse_config(const char *config_file, char *cluster_name, int *node, char *conninfo) { - char *s, buff[256]; + char *s, buff[1024]; FILE *fp = fopen (config_file, "r"); if (fp == NULL) diff --git a/strutil.h b/strutil.h index c2f5d55c..efefff7b 100644 --- a/strutil.h +++ b/strutil.h @@ -9,7 +9,7 @@ #define _STRUTIL_H_ #define QUERY_STR_LEN 8192 -#define MAXLEN 80 +#define MAXLEN 1024 extern int xsnprintf(char *str, size_t size, const char *format, ...); From faddaed316cb39b64bc87dc166ba712c5f1639c3 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Wed, 22 Dec 2010 15:01:35 -0800 Subject: [PATCH 11/34] Avoid a use-after-free in verbose logging Previously, this print would use memory freed by PQClear previously. Signed-off-by: Dan Farina --- repmgr.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/repmgr.c b/repmgr.c index 7eaca0f7..b9336011 100644 --- a/repmgr.c +++ b/repmgr.c @@ -974,6 +974,12 @@ stop_backup: return; } last_wal_segment = PQgetvalue(res, 0, 0); + + if (verbose) + printf( + _("%s requires primary to keep WAL files %s until at least %s\n"), + progname, first_wal_segment, last_wal_segment); + PQclear(res); PQfinish(conn); @@ -981,11 +987,6 @@ stop_backup: if (r != 0) return; - if (verbose) - printf( - _("%s requires primary to keep WAL files %s until at least %s\n"), - progname, first_wal_segment, last_wal_segment); - /* * We need to create the pg_xlog sub directory too, I'm reusing a variable * here. From 620974ba042b20e43bcac9cf22b11f25181fa763 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Wed, 22 Dec 2010 19:00:21 -0800 Subject: [PATCH 12/34] Fix unsafe string handling It looks like the old code would overflow in some cases. Signed-off-by: Dan Farina --- repmgr.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/repmgr.c b/repmgr.c index b9336011..9fc2c7ba 100644 --- a/repmgr.c +++ b/repmgr.c @@ -1217,9 +1217,20 @@ do_standby_follow(void) * before closing the connection because we will need them to * recreate the recovery.conf file */ - host = malloc(20); + + /* + * Copy the hostname to the 'host' global variable from the master + * connection. + */ + { + char *pqhost = PQhost(master_conn); + const int host_buf_sz = strlen(pqhost); + + host = malloc(host_buf_sz + 1); + xsnprintf(host, host_buf_sz, "%s", pqhost); + } + masterport = malloc(10); - strcpy(host, PQhost(master_conn)); strcpy(masterport, PQport(master_conn)); PQfinish(master_conn); From 29c39c21f6cfac32def1c7f0b82cca78e7bc2f47 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Wed, 22 Dec 2010 15:01:35 -0800 Subject: [PATCH 13/34] Avoid a use-after-free in verbose logging (again) Previously, this print would use memory freed by PQClear previously. Also allocate/free memory to prevent this tiny memory leak. Signed-off-by: Dan Farina --- repmgr.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/repmgr.c b/repmgr.c index 9fc2c7ba..c98e7148 100644 --- a/repmgr.c +++ b/repmgr.c @@ -623,8 +623,8 @@ do_standby_clone(void) char master_control_file[MAXLEN]; char local_control_file[MAXLEN]; - const char *first_wal_segment = NULL; - const char *last_wal_segment = NULL; + char *first_wal_segment = NULL; + const char *last_wal_segment = NULL; char master_version[MAXVERSIONSTR]; @@ -875,6 +875,16 @@ do_standby_clone(void) PQfinish(conn); return; } + + if (verbose) + { + char *first_wal_seg_pq = PQgetvalue(res, 0, 0); + size_t buf_sz = strlen(first_wal_seg_pq); + + first_wal_segment = malloc(buf_sz + 1); + xsnprintf(first_wal_segment, buf_sz, "%s", first_wal_seg_pq); + } + first_wal_segment = PQgetvalue(res, 0, 0); PQclear(res); @@ -976,10 +986,19 @@ stop_backup: last_wal_segment = PQgetvalue(res, 0, 0); if (verbose) + { printf( _("%s requires primary to keep WAL files %s until at least %s\n"), progname, first_wal_segment, last_wal_segment); + /* + * Only free the first_wal_segment since it was copied out of the + * pqresult. + */ + free(first_wal_segment); + first_wal_segment = NULL; + } + PQclear(res); PQfinish(conn); From f969dca821c4fecb9f951eaa434c72ee4c63a136 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Wed, 22 Dec 2010 19:43:32 -0800 Subject: [PATCH 14/34] Hack to get passwords in recovery.conf Signed-off-by: Dan Farina --- dbutils.c | 16 ++++++++++++++-- dbutils.h | 4 ++-- repmgr.c | 45 +++++++++++++++++++++++++++++++++++++-------- repmgrd.c | 4 ++-- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/dbutils.c b/dbutils.c index c89fe175..25a14f1f 100644 --- a/dbutils.c +++ b/dbutils.c @@ -163,18 +163,30 @@ get_cluster_size(PGconn *conn) /* * get a connection to master by reading repl_nodes, creating a connection * to each node (one at a time) and finding if it is a master or a standby + * + * NB: If master_conninfo_out may be NULL. If it is non-null, it is assumed to + * point to allocated memory of MAXCONNINFO in length, and the master server + * connection string is placed there. */ PGconn * getMasterConnection(PGconn *standby_conn, int id, char *cluster, - int *master_id) + int *master_id, char *master_conninfo_out) { PGconn *master_conn = NULL; PGresult *res1; PGresult *res2; char sqlquery[QUERY_STR_LEN]; - char master_conninfo[MAXCONNINFO]; + char master_conninfo_stack[MAXCONNINFO]; + char *master_conninfo = &*master_conninfo_stack; int i; + /* + * If the caller wanted to get a copy of the connection info string, sub + * out the local stack pointer for the pointer passed by the caller. + */ + if (master_conninfo_out != NULL) + master_conninfo = master_conninfo_out; + /* find all nodes belonging to this cluster */ sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes " " WHERE cluster = '%s' and id <> %d", diff --git a/dbutils.h b/dbutils.h index 5da99c36..10ee1900 100644 --- a/dbutils.h +++ b/dbutils.h @@ -10,5 +10,5 @@ char *pg_version(PGconn *conn, char* major_version); bool guc_setted(PGconn *conn, const char *parameter, const char *op, const char *value); const char *get_cluster_size(PGconn *conn); -PGconn * getMasterConnection(PGconn *standby_conn, int id, char *cluster, - int *master_id); +PGconn *getMasterConnection(PGconn *standby_conn, int id, char *cluster, + int *master_id, char *master_conninfo_out); diff --git a/repmgr.c b/repmgr.c index c98e7148..4403215c 100644 --- a/repmgr.c +++ b/repmgr.c @@ -35,7 +35,7 @@ static void help(const char *progname); -static bool create_recovery_file(const char *data_dir); +static bool create_recovery_file(const char *data_dir, char *master_conninfo); static int copy_remote_files(char *host, char *remote_user, char *remote_path, char *local_path, bool is_directory); static bool check_parameters_for_action(const int action); @@ -428,7 +428,8 @@ do_master_register(void) int id; /* Ensure there isn't any other master already registered */ - master_conn = getMasterConnection(conn, myLocalId, myClusterName, &id); + master_conn = getMasterConnection(conn, myLocalId, myClusterName, &id, + NULL); if (master_conn != NULL) { PQfinish(master_conn); @@ -543,7 +544,7 @@ do_standby_register(void) /* check if there is a master in this cluster */ master_conn = getMasterConnection(conn, myLocalId, myClusterName, - &master_id); + &master_id, NULL); if (!master_conn) return; @@ -1018,7 +1019,7 @@ stop_backup: } /* Finally, write the recovery.conf file */ - create_recovery_file(dest_dir); + create_recovery_file(dest_dir, NULL); /* * We don't start the service because we still may want to move the @@ -1084,7 +1085,7 @@ do_standby_promote(void) /* we also need to check if there isn't any master already */ old_master_conn = getMasterConnection(conn, myLocalId, myClusterName, - &old_master_id); + &old_master_id, NULL); if (old_master_conn != NULL) { PQfinish(old_master_conn); @@ -1153,6 +1154,7 @@ do_standby_follow(void) char myClusterName[MAXLEN]; int myLocalId = -1; char conninfo[MAXLEN]; + char master_conninfo[MAXLEN]; PGconn *master_conn; int master_id; @@ -1193,7 +1195,7 @@ do_standby_follow(void) /* we also need to check if there is any master in the cluster */ master_conn = getMasterConnection(conn, myLocalId, myClusterName, - &master_id); + &master_id, master_conninfo); if (master_conn == NULL) { PQfinish(conn); @@ -1273,7 +1275,7 @@ do_standby_follow(void) PQfinish(conn); /* write the recovery.conf file */ - if (!create_recovery_file(data_dir)) + if (!create_recovery_file(data_dir, master_conninfo)) return; /* Finally, restart the service */ @@ -1326,8 +1328,13 @@ help(const char *progname) } +/* + * Creates a recovery file for a standby. + * + * Writes master_conninfo to recovery.conf if is non-NULL + */ static bool -create_recovery_file(const char *data_dir) +create_recovery_file(const char *data_dir, char *master_conninfo) { FILE *recovery_file; char recovery_file_path[MAXLEN]; @@ -1350,6 +1357,28 @@ create_recovery_file(const char *data_dir) return false; } + if (master_conninfo == NULL) + { + char *password = getenv("PGPASSWORD"); + + if (password == NULL) + { + fprintf(stderr, + _("%s: Panic! PGPASSWORD not set, how can we get here?\n"), + progname); + exit(255); + } + + maxlen_snprintf(line, + "primary_conninfo = 'host=%s port=%s' password=%s\n", + host, ((masterport==NULL) ? "5432" : masterport), + password); + } + else + { + maxlen_snprintf(line, "primary_conninfo = '%s'\n", master_conninfo); + } + maxlen_snprintf(line, "primary_conninfo = 'host=%s port=%s'\n", host, ((masterport==NULL) ? "5432" : masterport)); if (fputs(line, recovery_file) == EOF) diff --git a/repmgrd.c b/repmgrd.c index 02df064f..16790566 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -168,7 +168,7 @@ main(int argc, char **argv) { /* I need the id of the primary as well as a connection to it */ primaryConn = getMasterConnection(myLocalConn, myLocalId, - myClusterName, &primaryId); + myClusterName, &primaryId, NULL); if (primaryConn == NULL) exit(1); } @@ -240,7 +240,7 @@ MonitorExecute(void) connection_retries++) { primaryConn = getMasterConnection(myLocalConn, myLocalId, - myClusterName, &primaryId); + myClusterName, &primaryId, NULL); if (PQstatus(primaryConn) == CONNECTION_OK) { /* Connected, we can continue the process so break the loop */ From 0bae682a0d276b1636a91cdcd9b74179f21218b8 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Thu, 23 Dec 2010 00:46:59 -0800 Subject: [PATCH 15/34] Fix off-by-one in passing buffer size to xsnprintf This would cause a consistent panic (exit() call) without reason. This should not enable any overruns (but check my work). Signed-off-by: Dan Farina --- repmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repmgr.c b/repmgr.c index 4403215c..eb07c67a 100644 --- a/repmgr.c +++ b/repmgr.c @@ -883,7 +883,7 @@ do_standby_clone(void) size_t buf_sz = strlen(first_wal_seg_pq); first_wal_segment = malloc(buf_sz + 1); - xsnprintf(first_wal_segment, buf_sz, "%s", first_wal_seg_pq); + xsnprintf(first_wal_segment, buf_sz + 1, "%s", first_wal_seg_pq); } first_wal_segment = PQgetvalue(res, 0, 0); From 1f098c60acfadb534effa7cc4a27d02d27067921 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Thu, 23 Dec 2010 00:49:24 -0800 Subject: [PATCH 16/34] Remove dead-ish code This is a leftover after having fixed various problems in the verbose output here. Signed-off-by: Dan Farina --- repmgr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/repmgr.c b/repmgr.c index eb07c67a..b111cefb 100644 --- a/repmgr.c +++ b/repmgr.c @@ -886,7 +886,6 @@ do_standby_clone(void) xsnprintf(first_wal_segment, buf_sz + 1, "%s", first_wal_seg_pq); } - first_wal_segment = PQgetvalue(res, 0, 0); PQclear(res); /* From 3a430397dc9893f7d7f374f4d4a1687926b062db Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Thu, 23 Dec 2010 00:53:01 -0800 Subject: [PATCH 17/34] Avoid overwriting the new password-in-recovery.conf formatting Previously: did that work, then threw it away/overwrote it. Signed-off-by: Dan Farina --- repmgr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/repmgr.c b/repmgr.c index b111cefb..a89b49ea 100644 --- a/repmgr.c +++ b/repmgr.c @@ -1378,8 +1378,6 @@ create_recovery_file(const char *data_dir, char *master_conninfo) maxlen_snprintf(line, "primary_conninfo = '%s'\n", master_conninfo); } - maxlen_snprintf(line, "primary_conninfo = 'host=%s port=%s'\n", host, - ((masterport==NULL) ? "5432" : masterport)); if (fputs(line, recovery_file) == EOF) { fprintf(stderr, "recovery file could not be written, it could be necesary to create it manually\n"); From dd5ac660bfb7d0257b8715ffb16befdabae04469 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Thu, 23 Dec 2010 00:53:31 -0800 Subject: [PATCH 18/34] Comments and cleanup Signed-off-by: Dan Farina --- repmgr.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/repmgr.c b/repmgr.c index a89b49ea..ee424a98 100644 --- a/repmgr.c +++ b/repmgr.c @@ -1356,6 +1356,14 @@ create_recovery_file(const char *data_dir, char *master_conninfo) return false; } + /* + * Template a password into the connection string in recovery.conf. + * Sometimes this is passed by the user explicitly, and otherwise we try to + * get it into th environment + * + * XXX: This is pretty dirty, at least push this up to the caller rather + * than hitting environment variables at this level. + */ if (master_conninfo == NULL) { char *password = getenv("PGPASSWORD"); @@ -1374,9 +1382,7 @@ create_recovery_file(const char *data_dir, char *master_conninfo) password); } else - { maxlen_snprintf(line, "primary_conninfo = '%s'\n", master_conninfo); - } if (fputs(line, recovery_file) == EOF) { From 156714f3f184ac408a8279f52fd00388b3310958 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Thu, 23 Dec 2010 01:03:44 -0800 Subject: [PATCH 19/34] Fix quoting misbehavior Move the single quote in the formatting string to the end of the line. Signed-off-by: Dan Farina --- repmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repmgr.c b/repmgr.c index ee424a98..695137ee 100644 --- a/repmgr.c +++ b/repmgr.c @@ -1377,7 +1377,7 @@ create_recovery_file(const char *data_dir, char *master_conninfo) } maxlen_snprintf(line, - "primary_conninfo = 'host=%s port=%s' password=%s\n", + "primary_conninfo = 'host=%s port=%s password=%s'\n", host, ((masterport==NULL) ? "5432" : masterport), password); } From cb1192b9129ec2377541d9648011cd18e62ef296 Mon Sep 17 00:00:00 2001 From: trbs Date: Thu, 23 Dec 2010 15:02:02 +0100 Subject: [PATCH 20/34] fix strformat order reversal in error message --- repmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repmgr.c b/repmgr.c index 8e2ce895..8efff87f 100644 --- a/repmgr.c +++ b/repmgr.c @@ -723,7 +723,7 @@ do_standby_clone(void) if (!guc_setted(conn, "wal_keep_segments", ">=", wal_keep_segments)) { PQfinish(conn); - fprintf(stderr, _("%s needs parameter 'wal_keep_segments' to be set to %s or greater\n"), wal_keep_segments, progname); + fprintf(stderr, _("%s needs parameter 'wal_keep_segments' to be set to %s or greater\n"), progname, wal_keep_segments); return; } if (!guc_setted(conn, "archive_mode", "=", "on")) From cf5717ad597cb55d94d011ce494d888a16a64d74 Mon Sep 17 00:00:00 2001 From: trbs Date: Thu, 23 Dec 2010 15:02:23 +0100 Subject: [PATCH 21/34] Updated README with Debian/Ubuntu install information --- README.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.rst b/README.rst index 966ae4de..1a7993a9 100644 --- a/README.rst +++ b/README.rst @@ -126,6 +126,30 @@ path either. The following recipe should work:: sudo PATH="/usr/pgsql-9.0/bin:$PATH" make USE_PGXS=1 install +Notes on Ubuntu, Debian or other Debian-based Builds +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Debian packages of PostgreSQL put ``pg_config`` into the development package +called ``postgresql-server-dev-$version``. + +When building repmgr against a Debian packages build, you may discover that some +development packages are needed as well. You will need the following development +packages installed:: + + sudo apt-get install libxslt1-dev libxml2-dev libpam-dev libedit-dev + +If you build and install repmgr manually it will not be on the system path. The +binaries will be installed in /usr/lib/postgresql/$version/bin/ which is not on +the default path. The reason behind this is that Ubuntu/Debian systems manage +multiple installed versions of PostgreSQL on the same system through a wrapper +called pg_wrapper and repmgr is not (yet) known to this wrapper. + +You can solve this in many different ways, the most Debian like is to make an +alternate for repmgr and repmgrd:: + + sudo update-alternatives --install /usr/bin/repmgr repmgr /usr/lib/postgresql/9.0/bin/repmgr 10 + sudo update-alternatives --install /usr/bin/repmgrd repmgrd /usr/lib/postgresql/9.0/bin/repmgrd 10 + Confirm software was built correctly ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 745392e3a2f66734409f2a89154819cdc51703df Mon Sep 17 00:00:00 2001 From: trbs Date: Thu, 6 Jan 2011 23:46:21 +0100 Subject: [PATCH 22/34] added readme.html to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 349c5013..71670b00 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.o repmgr repmgrd +README.html From 4a0e8274643fd2eaeb993f8dfdaf1663ebc9a8aa Mon Sep 17 00:00:00 2001 From: trbs Date: Fri, 7 Jan 2011 01:32:31 +0100 Subject: [PATCH 23/34] fix line --- README.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 1a7993a9..48c66109 100644 --- a/README.rst +++ b/README.rst @@ -160,8 +160,7 @@ is available by checking its version:: repmgr --version repmgrd --version -You may need to include -the full path of the binary instead, such as this RHEL example:: +You may need to include the full path of the binary instead, such as this RHEL example:: /usr/pgsql-9.0/bin/repmgr --version /usr/pgsql-9.0/bin/repmgrd --version From fc2405f17df5ec370c084b11527d1219abfc4d84 Mon Sep 17 00:00:00 2001 From: trbs Date: Fri, 7 Jan 2011 01:36:46 +0100 Subject: [PATCH 24/34] use struct for config file information --- config.c | 37 ++++++++++++---- config.h | 9 +++- repmgr.c | 124 ++++++++++++++++-------------------------------------- repmgr.h | 4 +- repmgrd.c | 32 +++++++------- 5 files changed, 92 insertions(+), 114 deletions(-) diff --git a/config.c b/config.c index 4499509f..43843581 100644 --- a/config.c +++ b/config.c @@ -22,7 +22,7 @@ #define MAXLINELENGTH 4096 void -parse_config(const char *config_file, char *cluster_name, int *node, char *conninfo) +parse_config(const char *config_file, repmgr_config *config) { char *s, buff[MAXLINELENGTH]; char name[MAXLEN]; @@ -30,9 +30,16 @@ parse_config(const char *config_file, char *cluster_name, int *node, char *conni FILE *fp = fopen (config_file, "r"); - if (fp == NULL) - return; - + if (fp == NULL) { + fprintf(stderr, _("Could not find configuration file '%s'\n"), config_file); + exit(1); + } + + /* Initialize */ + memset(config->cluster_name, 0, sizeof(config->cluster_name)); + config->node = -1; + memset(config->conninfo, 0, sizeof(config->conninfo)); + /* Read next line */ while ((s = fgets (buff, sizeof buff, fp)) != NULL) { @@ -45,18 +52,32 @@ parse_config(const char *config_file, char *cluster_name, int *node, char *conni /* Copy into correct entry in parameters struct */ if (strcmp(name, "cluster") == 0) - strncpy (cluster_name, value, MAXLEN); + strncpy (config->cluster_name, value, MAXLEN); else if (strcmp(name, "node") == 0) - *node = atoi(value); + config->node = atoi(value); else if (strcmp(name, "conninfo") == 0) - strncpy (conninfo, value, MAXLEN); + strncpy (config->conninfo, value, MAXLEN); else printf ("WARNING: %s/%s: Unknown name/value pair!\n", name, value); } - /* Close file */ fclose (fp); + + /* Check config settings */ + if (strnlen(config->cluster_name, MAXLEN)==0) + { + fprintf(stderr, "Cluster name is missing. " + "Check the configuration file.\n"); + exit(1); + } + + if (config->node == -1) + { + fprintf(stderr, "Node information is missing. " + "Check the configuration file.\n"); + exit(1); + } } char * diff --git a/config.h b/config.h index 9b2ea3fc..e4710ea8 100644 --- a/config.h +++ b/config.h @@ -17,6 +17,13 @@ * */ -void parse_config(const char *config_file, char *cluster_name, int *node, char *service); +typedef struct +{ + char cluster_name[MAXLEN]; + int node; + char conninfo[MAXLEN]; +} repmgr_config; + +void parse_config(const char *config_file, repmgr_config *config); void parse_line(char *buff, char *name, char *value); char *trim(char *s); diff --git a/repmgr.c b/repmgr.c index 8efff87f..26ebe7cd 100644 --- a/repmgr.c +++ b/repmgr.c @@ -43,8 +43,6 @@ #define STANDBY_PROMOTE 4 #define STANDBY_FOLLOW 5 -#define QUERY_STR_LEN 8192 - static void help(const char *progname); static bool create_recovery_file(const char *data_dir); static int copy_remote_files(char *host, char *remote_user, char *remote_path, char *local_path, bool is_directory); @@ -77,6 +75,7 @@ char *masterport = NULL; char *server_mode = NULL; char *server_cmd = NULL; +repmgr_config config = {}; int main(int argc, char **argv) @@ -253,6 +252,17 @@ main(int argc, char **argv) else dbname = "postgres"; } + + /* + * Read the configuration file: repmgr.conf + */ + parse_config(config_file, &config); + if (config.node == -1) + { + fprintf(stderr, "Node information is missing. " + "Check the configuration file.\n"); + exit(1); + } keywords[2] = "user"; values[2] = username; @@ -296,25 +306,10 @@ do_master_register(void) PGresult *res; char sqlquery[QUERY_STR_LEN]; - char myClusterName[MAXLEN]; - int myLocalId = -1; - char conninfo[MAXLEN]; - bool schema_exists = false; char master_version[MAXVERSIONSTR]; - /* - * Read the configuration file: repmgr.conf - */ - parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) - { - fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); - exit(1); - } - - conn = establishDBConnection(conninfo, true); + conn = establishDBConnection(config.conninfo, true); /* master should be v9 or better */ pg_version(conn, master_version); @@ -334,7 +329,7 @@ do_master_register(void) } /* Check if there is a schema for this cluster */ - sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", myClusterName); + sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", config.cluster_name); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -348,7 +343,7 @@ do_master_register(void) { if (!force) /* and we are not forcing so error */ { - fprintf(stderr, "Schema repmgr_%s already exists.", myClusterName); + fprintf(stderr, "Schema repmgr_%s already exists.", config.cluster_name); PQclear(res); PQfinish(conn); return; @@ -360,11 +355,11 @@ do_master_register(void) if (!schema_exists) { /* ok, create the schema */ - sprintf(sqlquery, "CREATE SCHEMA repmgr_%s", myClusterName); + sprintf(sqlquery, "CREATE SCHEMA repmgr_%s", config.cluster_name); if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot create the schema repmgr_%s: %s\n", - myClusterName, PQerrorMessage(conn)); + config.cluster_name, PQerrorMessage(conn)); PQfinish(conn); return; } @@ -373,11 +368,11 @@ do_master_register(void) sprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( " " id integer primary key, " " cluster text not null, " - " conninfo text not null)", myClusterName); + " conninfo text not null)", config.cluster_name); if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot create the table repmgr_%s.repl_nodes: %s\n", - myClusterName, PQerrorMessage(conn)); + config.cluster_name, PQerrorMessage(conn)); PQfinish(conn); return; } @@ -389,11 +384,11 @@ do_master_register(void) " last_wal_primary_location TEXT NOT NULL, " " last_wal_standby_location TEXT NOT NULL, " " replication_lag BIGINT NOT NULL, " - " apply_lag BIGINT NOT NULL) ", myClusterName); + " apply_lag BIGINT NOT NULL) ", config.cluster_name); if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot create the table repmgr_%s.repl_monitor: %s\n", - myClusterName, PQerrorMessage(conn)); + config.cluster_name, PQerrorMessage(conn)); PQfinish(conn); return; } @@ -407,11 +402,11 @@ do_master_register(void) " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " " FROM monitor_info a " - " WHERE row_number = 1", myClusterName, myClusterName); + " WHERE row_number = 1", config.cluster_name, config.cluster_name); if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot create the view repmgr_%s.repl_status: %s\n", - myClusterName, PQerrorMessage(conn)); + config.cluster_name, PQerrorMessage(conn)); PQfinish(conn); return; } @@ -422,7 +417,7 @@ do_master_register(void) int id; /* Ensure there isn't any other master already registered */ - master_conn = getMasterConnection(conn, myLocalId, myClusterName, &id); + master_conn = getMasterConnection(conn, config.node, config.cluster_name, &id); if (master_conn != NULL) { PQfinish(master_conn); @@ -436,7 +431,7 @@ do_master_register(void) { sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " " WHERE id = %d", - myClusterName, myLocalId); + config.cluster_name, config.node); if (!PQexec(conn, sqlquery)) { @@ -449,7 +444,7 @@ do_master_register(void) sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " "VALUES (%d, '%s', '%s')", - myClusterName, myLocalId, myClusterName, conninfo); + config.cluster_name, config.node, config.cluster_name, config.conninfo); if (!PQexec(conn, sqlquery)) { @@ -474,25 +469,10 @@ do_standby_register(void) PGresult *res; char sqlquery[QUERY_STR_LEN]; - char myClusterName[MAXLEN]; - int myLocalId = -1; - char conninfo[MAXLEN]; - char master_version[MAXVERSIONSTR]; char standby_version[MAXVERSIONSTR]; - /* - * Read the configuration file: repmgr.conf - */ - parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) - { - fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); - exit(1); - } - - conn = establishDBConnection(conninfo, true); + conn = establishDBConnection(config.conninfo, true); /* should be v9 or better */ pg_version(conn, standby_version); @@ -512,7 +492,7 @@ do_standby_register(void) } /* Check if there is a schema for this cluster */ - sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", myClusterName); + sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", config.cluster_name); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -524,7 +504,7 @@ do_standby_register(void) if (PQntuples(res) == 0) /* schema doesn't exists */ { - fprintf(stderr, "Schema repmgr_%s doesn't exists.", myClusterName); + fprintf(stderr, "Schema repmgr_%s doesn't exists.", config.cluster_name); PQclear(res); PQfinish(conn); return; @@ -532,7 +512,7 @@ do_standby_register(void) PQclear(res); /* check if there is a master in this cluster */ - master_conn = getMasterConnection(conn, myLocalId, myClusterName, &master_id); + master_conn = getMasterConnection(conn, config.node, config.cluster_name, &master_id); if (!master_conn) return; @@ -562,7 +542,7 @@ do_standby_register(void) { sprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " " WHERE id = %d", - myClusterName, myLocalId); + config.cluster_name, config.node); if (!PQexec(master_conn, sqlquery)) { @@ -576,7 +556,7 @@ do_standby_register(void) sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " "VALUES (%d, '%s', '%s')", - myClusterName, myLocalId, myClusterName, conninfo); + config.cluster_name, config.node, config.cluster_name, config.conninfo); if (!PQexec(master_conn, sqlquery)) { @@ -970,10 +950,6 @@ do_standby_promote(void) char sqlquery[QUERY_STR_LEN]; char script[QUERY_STR_LEN]; - char myClusterName[MAXLEN]; - int myLocalId = -1; - char conninfo[MAXLEN]; - PGconn *old_master_conn; int old_master_id; @@ -984,19 +960,8 @@ do_standby_promote(void) char standby_version[MAXVERSIONSTR]; - /* - * Read the configuration file: repmgr.conf - */ - parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) - { - fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); - exit(1); - } - /* We need to connect to check configuration */ - conn = establishDBConnection(conninfo, true); + conn = establishDBConnection(config.conninfo, true); /* we need v9 or better */ pg_version(conn, standby_version); @@ -1015,7 +980,7 @@ do_standby_promote(void) } /* we also need to check if there isn't any master already */ - old_master_conn = getMasterConnection(conn, myLocalId, myClusterName, &old_master_id); + old_master_conn = getMasterConnection(conn, config.node, config.cluster_name, &old_master_id); if (old_master_conn != NULL) { PQfinish(old_master_conn); @@ -1058,7 +1023,7 @@ do_standby_promote(void) /* * XXX i'm removing this because it gives an annoying message saying couldn't connect * but is just the server starting up - * conn = establishDBConnection(conninfo, true); + * conn = establishDBConnection(config.conninfo, true); * if (is_standby(conn)) * fprintf(stderr, "\n%s: STANDBY PROMOTE failed, this is still a standby node.\n", progname); * else @@ -1078,10 +1043,6 @@ do_standby_follow(void) char sqlquery[QUERY_STR_LEN]; char script[QUERY_STR_LEN]; - char myClusterName[MAXLEN]; - int myLocalId = -1; - char conninfo[MAXLEN]; - PGconn *master_conn; int master_id; @@ -1091,19 +1052,8 @@ do_standby_follow(void) char master_version[MAXVERSIONSTR]; char standby_version[MAXVERSIONSTR]; - /* - * Read the configuration file: repmgr.conf - */ - parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) - { - fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); - exit(1); - } - /* We need to connect to check configuration */ - conn = establishDBConnection(conninfo, true); + conn = establishDBConnection(config.conninfo, true); /* Check we are in a standby node */ if (!is_standby(conn)) @@ -1122,7 +1072,7 @@ do_standby_follow(void) } /* we also need to check if there is any master in the cluster */ - master_conn = getMasterConnection(conn, myLocalId, myClusterName, &master_id); + master_conn = getMasterConnection(conn, config.node, config.cluster_name, &master_id); if (master_conn == NULL) { PQfinish(conn); diff --git a/repmgr.h b/repmgr.h index ec32b995..78b9edbc 100644 --- a/repmgr.h +++ b/repmgr.h @@ -25,7 +25,6 @@ #include "libpq-fe.h" #include "dbutils.h" -#include "config.h" #define PRIMARY_MODE 0 @@ -34,5 +33,8 @@ #define MAXLEN 80 #define CONFIG_FILE "repmgr.conf" #define MAXVERSIONSTR 16 +#define QUERY_STR_LEN 8192 + +#include "config.h" #endif diff --git a/repmgrd.c b/repmgrd.c index b7e0d1b5..65fde42d 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -30,11 +30,8 @@ #include "libpq/pqsignal.h" -char myClusterName[MAXLEN]; - /* Local info */ int myLocalMode = STANDBY_MODE; -int myLocalId = -1; PGconn *myLocalConn; /* Primary info */ @@ -49,6 +46,8 @@ const char *progname; char *config_file = NULL; bool verbose = false; +// should initialize with {0} to be ANSI complaint ? but this raises error with gcc -Wall +repmgr_config config = {}; static void help(const char *progname); static void checkClusterConfiguration(void); @@ -94,7 +93,6 @@ main(int argc, char **argv) int optindex; int c; - char conninfo[MAXLEN]; char standby_version[MAXVERSIONSTR]; progname = get_progname(argv[0]); @@ -141,15 +139,15 @@ main(int argc, char **argv) /* * Read the configuration file: repmgr.conf */ - parse_config(config_file, myClusterName, &myLocalId, conninfo); - if (myLocalId == -1) + parse_config(config_file, &config); + if (config.node == -1) { fprintf(stderr, "Node information is missing. " "Check the configuration file.\n"); exit(1); } - myLocalConn = establishDBConnection(conninfo, true); + myLocalConn = establishDBConnection(config.conninfo, true); /* should be v9 or better */ pg_version(myLocalConn, standby_version); @@ -167,20 +165,20 @@ main(int argc, char **argv) myLocalMode = is_standby(myLocalConn) ? STANDBY_MODE : PRIMARY_MODE; if (myLocalMode == PRIMARY_MODE) { - primaryId = myLocalId; - strcpy(primaryConninfo, conninfo); + primaryId = config.node; + strcpy(primaryConninfo, config.conninfo); primaryConn = myLocalConn; } else { /* I need the id of the primary as well as a connection to it */ - primaryConn = getMasterConnection(myLocalConn, myLocalId, myClusterName, &primaryId); + primaryConn = getMasterConnection(myLocalConn, config.node, config.cluster_name, &primaryId); if (primaryConn == NULL) exit(1); } checkClusterConfiguration(); - checkNodeConfiguration(conninfo); + checkNodeConfiguration(config.conninfo); if (myLocalMode == STANDBY_MODE) { MonitorCheck(); @@ -239,7 +237,7 @@ MonitorExecute(void) fprintf(stderr, "%s: another node has been promoted.\n", progname); for (connection_retries = 0; connection_retries < 6; connection_retries++) { - primaryConn = getMasterConnection(myLocalConn, myLocalId, myClusterName, &primaryId); + primaryConn = getMasterConnection(myLocalConn, config.node, config.cluster_name, &primaryId); if (PQstatus(primaryConn) == CONNECTION_OK) { /* Connected, we can continue the process so break the loop */ @@ -322,8 +320,8 @@ MonitorExecute(void) "INSERT INTO repmgr_%s.repl_monitor " "VALUES(%d, %d, '%s'::timestamp with time zone, " " '%s', '%s', " - " %lld, %lld)", myClusterName, - primaryId, myLocalId, monitor_standby_timestamp, + " %lld, %lld)", config.cluster_name, + primaryId, config.node, monitor_standby_timestamp, last_wal_primary_location, last_wal_standby_received, (lsn_primary - lsn_standby_received), @@ -346,7 +344,7 @@ checkClusterConfiguration(void) sprintf(sqlquery, "SELECT oid FROM pg_class " " WHERE oid = 'repmgr_%s.repl_nodes'::regclass", - myClusterName); + config.cluster_name); res = PQexec(myLocalConn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -384,7 +382,7 @@ checkNodeConfiguration(char *conninfo) */ sprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes " " WHERE id = %d AND cluster = '%s' ", - myClusterName, myLocalId, myClusterName); + config.cluster_name, config.node, config.cluster_name); res = PQexec(myLocalConn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -406,7 +404,7 @@ checkNodeConfiguration(char *conninfo) /* Adding the node */ sprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " "VALUES (%d, '%s', '%s')", - myClusterName, myLocalId, myClusterName, conninfo); + config.cluster_name, config.node, config.cluster_name, conninfo); if (!PQexec(primaryConn, sqlquery)) { From 57169f51cfa6da0b7082d1457f4c2f6bf9746879 Mon Sep 17 00:00:00 2001 From: trbs Date: Sat, 8 Jan 2011 01:46:39 +0100 Subject: [PATCH 25/34] made rsync_options configurable --- config.c | 3 +++ config.h | 1 + repmgr.c | 6 +++++- repmgr.conf | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/config.c b/config.c index 43843581..c3df1b89 100644 --- a/config.c +++ b/config.c @@ -39,6 +39,7 @@ parse_config(const char *config_file, repmgr_config *config) memset(config->cluster_name, 0, sizeof(config->cluster_name)); config->node = -1; memset(config->conninfo, 0, sizeof(config->conninfo)); + memset(config->rsync_options, 0, sizeof(config->rsync_options)); /* Read next line */ while ((s = fgets (buff, sizeof buff, fp)) != NULL) @@ -57,6 +58,8 @@ parse_config(const char *config_file, repmgr_config *config) config->node = atoi(value); else if (strcmp(name, "conninfo") == 0) strncpy (config->conninfo, value, MAXLEN); + else if (strcmp(name, "rsync_options") == 0) + strncpy (config->rsync_options, value, QUERY_STR_LEN); else printf ("WARNING: %s/%s: Unknown name/value pair!\n", name, value); } diff --git a/config.h b/config.h index e4710ea8..b66bc6e4 100644 --- a/config.h +++ b/config.h @@ -22,6 +22,7 @@ typedef struct char cluster_name[MAXLEN]; int node; char conninfo[MAXLEN]; + char rsync_options[QUERY_STR_LEN]; } repmgr_config; void parse_config(const char *config_file, repmgr_config *config); diff --git a/repmgr.c b/repmgr.c index 26ebe7cd..b8d2540a 100644 --- a/repmgr.c +++ b/repmgr.c @@ -1237,7 +1237,11 @@ copy_remote_files(char *host, char *remote_user, char *remote_path, char *local_ char host_string[QUERY_STR_LEN]; int r; - sprintf(options, "--archive --checksum --compress --progress --rsh=ssh"); + if (strnlen(config.rsync_options, QUERY_STR_LEN) == 0) + sprintf(options, "--archive --checksum --compress --progress --rsh=ssh"); + else + strncpy(options, config.rsync_options, QUERY_STR_LEN); + if (force) strcat(options, " --delete"); diff --git a/repmgr.conf b/repmgr.conf index f7287502..a707dc42 100644 --- a/repmgr.conf +++ b/repmgr.conf @@ -1,3 +1,4 @@ cluster=test node=2 conninfo='host=192.168.204.104' +rsync_options=--archive --checksum --compress --progress --rsh=ssh From 1999b534fd1c72cff2bf206442f6b14a3b36f77f Mon Sep 17 00:00:00 2001 From: trbs Date: Tue, 11 Jan 2011 18:24:17 +0100 Subject: [PATCH 26/34] added note about postgresql-server-dev-9.0 and use libxslt-dev instead of version specific package name --- README.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 48c66109..ddbca1de 100644 --- a/README.rst +++ b/README.rst @@ -136,7 +136,12 @@ When building repmgr against a Debian packages build, you may discover that some development packages are needed as well. You will need the following development packages installed:: - sudo apt-get install libxslt1-dev libxml2-dev libpam-dev libedit-dev + sudo apt-get install libxslt-dev libxml2-dev libpam-dev libedit-dev + +If your using Debian packages for PostgreSQL and are building repmgr with the +USE_PGXS option you also need to install the corresponding development package:: + + sudo apt-get install postgresql-server-dev-9.0 If you build and install repmgr manually it will not be on the system path. The binaries will be installed in /usr/lib/postgresql/$version/bin/ which is not on From bfd3aed33bdf9933fad7ad26c8f9b02ba1704f25 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Sun, 6 Feb 2011 18:32:49 -0800 Subject: [PATCH 27/34] Fix a myriad of problems introduced by merging Signed-off-by: Dan Farina --- config.c | 4 +-- config.h | 15 ++++++--- dbutils.c | 2 +- repmgr.c | 97 ++++++++++++++++++++++++++++++------------------------- repmgr.h | 9 +++--- repmgrd.c | 8 +++-- strutil.h | 3 ++ 7 files changed, 79 insertions(+), 59 deletions(-) diff --git a/config.c b/config.c index 5fdd411e..868ec72a 100644 --- a/config.c +++ b/config.c @@ -17,14 +17,12 @@ * */ +#include "config.h" #include "repmgr.h" - #include "strutil.h" - void parse_config(const char *config_file, repmgr_config *config) - char *conninfo) { char *s, buff[MAXLINELENGTH]; char name[MAXLEN]; diff --git a/config.h b/config.h index b66bc6e4..9241d1d0 100644 --- a/config.h +++ b/config.h @@ -16,15 +16,22 @@ * along with this program. If not, see . * */ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include "strutil.h" + typedef struct { - char cluster_name[MAXLEN]; - int node; - char conninfo[MAXLEN]; - char rsync_options[QUERY_STR_LEN]; + char cluster_name[MAXLEN]; + int node; + char conninfo[MAXLEN]; + char rsync_options[QUERY_STR_LEN]; } repmgr_config; void parse_config(const char *config_file, repmgr_config *config); void parse_line(char *buff, char *name, char *value); char *trim(char *s); + +#endif diff --git a/dbutils.c b/dbutils.c index 2ac009b3..b2c90ea5 100644 --- a/dbutils.c +++ b/dbutils.c @@ -199,7 +199,7 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, /* find all nodes belonging to this cluster */ sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes " " WHERE cluster = '%s' and id <> %d", - cluster, cluster, id); + cluster, cluster, id); res1 = PQexec(standby_conn, sqlquery); if (PQresultStatus(res1) != PGRES_TUPLES_OK) diff --git a/repmgr.c b/repmgr.c index d9376701..eebf06f6 100644 --- a/repmgr.c +++ b/repmgr.c @@ -341,7 +341,8 @@ do_master_register(void) } /* Check if there is a schema for this cluster */ - sqlquery_sprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", config.cluster_name); + sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace " + "WHERE nspname = 'repmgr_%s'", config.cluster_name); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -372,7 +373,7 @@ do_master_register(void) if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot create the schema repmgr_%s: %s\n", - config.cluster_name, PQerrorMessage(conn)); + config.cluster_name, PQerrorMessage(conn)); PQfinish(conn); return; } @@ -381,11 +382,11 @@ do_master_register(void) sqlquery_snprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( " " id integer primary key, " " cluster text not null, " - " conninfo text not null)", config.cluster_name); + " conninfo text not null)", config.cluster_name); if (!PQexec(conn, sqlquery)) { fprintf(stderr, - config.cluster_name, PQerrorMessage(conn)); + config.cluster_name, PQerrorMessage(conn)); PQfinish(conn); return; } @@ -397,33 +398,34 @@ do_master_register(void) " last_wal_primary_location TEXT NOT NULL, " " last_wal_standby_location TEXT NOT NULL, " " replication_lag BIGINT NOT NULL, " - " apply_lag BIGINT NOT NULL) ", config.cluster_name); - myClusterName); - if (!PQexec(conn, sqlquery)) - { - fprintf(stderr, - config.cluster_name, PQerrorMessage(conn)); - PQfinish(conn); - return; - } + " apply_lag BIGINT NOT NULL) ", + config.cluster_name); + } - /* and the view */ - sqlquery_snprintf(sqlquery, "CREATE VIEW repmgr_%s.repl_status AS " - " WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node " - " ORDER BY last_monitor_time desc) " - " FROM repmgr_%s.repl_monitor) " - " SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, " - " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " - " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " - " FROM monitor_info a " - " WHERE row_number = 1", config.cluster_name, config.cluster_name); - if (!PQexec(conn, sqlquery)) - { - fprintf(stderr, - config.cluster_name, PQerrorMessage(conn)); - PQfinish(conn); - return; - } + if (!PQexec(conn, sqlquery)) + { + fprintf(stderr, + config.cluster_name, PQerrorMessage(conn)); + PQfinish(conn); + return; + } + + /* and the view */ + sqlquery_snprintf(sqlquery, "CREATE VIEW repmgr_%s.repl_status AS " + " WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node " + " ORDER BY last_monitor_time desc) " + " FROM repmgr_%s.repl_monitor) " + " SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, " + " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " + " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " + " FROM monitor_info a " + " WHERE row_number = 1", config.cluster_name, config.cluster_name); + if (!PQexec(conn, sqlquery)) + { + fprintf(stderr, + config.cluster_name, PQerrorMessage(conn)); + PQfinish(conn); + return; } else { @@ -431,8 +433,9 @@ do_master_register(void) int id; /* Ensure there isn't any other master already registered */ - master_conn = getMasterConnection(conn, config.node, config.cluster_name, &id); - NULL); + master_conn = getMasterConnection(conn, config.node, + config.cluster_name, &id, NULL); + if (master_conn != NULL) { PQfinish(master_conn); @@ -446,7 +449,7 @@ do_master_register(void) { sqlquery_snprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " " WHERE id = %d", - config.cluster_name, config.node); + config.cluster_name, config.node); if (!PQexec(conn, sqlquery)) { @@ -459,7 +462,8 @@ do_master_register(void) sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " "VALUES (%d, '%s', '%s')", - config.cluster_name, config.node, config.cluster_name, config.conninfo); + config.cluster_name, config.node, config.cluster_name, + config.conninfo); if (!PQexec(conn, sqlquery)) { @@ -508,9 +512,9 @@ do_standby_register(void) } /* Check if there is a schema for this cluster */ - sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", config.cluster_name); - "SELECT 1 FROM pg_namespace WHERE nspname = 'repmgr_%s'", - myClusterName); + sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace " + "WHERE nspname = 'repmgr_%s'", config.cluster_name); + res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -531,8 +535,9 @@ do_standby_register(void) PQclear(res); /* check if there is a master in this cluster */ - master_conn = getMasterConnection(conn, config.node, config.cluster_name, &master_id); + master_conn = getMasterConnection(conn, config.node, config.cluster_name, &master_id, NULL); + if (!master_conn) return; @@ -1056,7 +1061,8 @@ do_standby_promote(void) } /* we also need to check if there isn't any master already */ - old_master_conn = getMasterConnection(conn, config.node, config.cluster_name, &old_master_id); + old_master_conn = getMasterConnection(conn, config.node, config.cluster_name, + &old_master_id, NULL); if (old_master_conn != NULL) { @@ -1152,7 +1158,8 @@ do_standby_follow(void) } /* we also need to check if there is any master in the cluster */ - master_conn = getMasterConnection(conn, config.node, config.cluster_name, &master_id); + master_conn = getMasterConnection(conn, config.node, config.cluster_name, + &master_id, (char *) &master_conninfo); if (master_conn == NULL) { @@ -1366,11 +1373,13 @@ copy_remote_files(char *host, char *remote_user, char *remote_path, char host_string[MAXLEN]; int r; - if (strnlen(config.rsync_options, QUERY_STR_LEN) == 0) - sprintf(options, "--archive --checksum --compress --progress --rsh=ssh"); + if (strnlen(config.rsync_options, MAXLEN) == 0) + maxlen_snprintf( + options, "%s", + "--archive --checksum --compress --progress --rsh=ssh"); else - strncpy(options, config.rsync_options, QUERY_STR_LEN); - + maxlen_snprintf(options, "%s", config.rsync_options); + if (force) strcat(options, " --delete"); diff --git a/repmgr.h b/repmgr.h index accf6d0e..770063b1 100644 --- a/repmgr.h +++ b/repmgr.h @@ -17,14 +17,14 @@ * along with this program. If not, see . * */ - -#ifndef _REPMGR_H_ -#define _REPMGR_H_ - #include "postgres_fe.h" #include "getopt_long.h" #include "libpq-fe.h" + +#ifndef _REPMGR_H_ +#define _REPMGR_H_ + #include "dbutils.h" @@ -32,7 +32,6 @@ #define STANDBY_MODE 1 #define CONFIG_FILE "repmgr.conf" -#define QUERY_STR_LEN 8192 #include "config.h" diff --git a/repmgrd.c b/repmgrd.c index bfde9fea..f31c452f 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -178,7 +178,9 @@ main(int argc, char **argv) else { /* I need the id of the primary as well as a connection to it */ - primaryConn = getMasterConnection(myLocalConn, config.node, config.cluster_name, &primaryId); + primaryConn = getMasterConnection(myLocalConn, config.node, + config.cluster_name, &primaryId, + NULL); if (primaryConn == NULL) exit(1); @@ -249,7 +251,9 @@ MonitorExecute(void) for (connection_retries = 0; connection_retries < 6; connection_retries++) { - primaryConn = getMasterConnection(myLocalConn, config.node, config.cluster_name, &primaryId); + primaryConn = getMasterConnection(myLocalConn, config.node, + config.cluster_name, &primaryId, + NULL); if (PQstatus(primaryConn) == CONNECTION_OK) { diff --git a/strutil.h b/strutil.h index 68c6b5c2..41d9626e 100644 --- a/strutil.h +++ b/strutil.h @@ -8,6 +8,9 @@ #ifndef _STRUTIL_H_ #define _STRUTIL_H_ +#include + + #define QUERY_STR_LEN 8192 #define MAXLEN 1024 #define MAXLINELENGTH 4096 From c1b84fe9fcbc4ae529192476839cdb157b01ed43 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Sun, 6 Feb 2011 19:35:20 -0800 Subject: [PATCH 28/34] Make some fast hacks to quote schema names Signed-off-by: Dan Farina --- dbutils.c | 33 ++++++++++++++++------ repmgr.c | 82 ++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 82 insertions(+), 33 deletions(-) diff --git a/dbutils.c b/dbutils.c index b2c90ea5..5cc82397 100644 --- a/dbutils.c +++ b/dbutils.c @@ -181,12 +181,15 @@ PGconn * getMasterConnection(PGconn *standby_conn, int id, char *cluster, int *master_id, char *master_conninfo_out) { - PGconn *master_conn = NULL; - PGresult *res1; - PGresult *res2; - char sqlquery[QUERY_STR_LEN]; - char master_conninfo_stack[MAXCONNINFO]; - char *master_conninfo = &*master_conninfo_stack; + PGconn *master_conn = NULL; + PGresult *res1; + PGresult *res2; + char sqlquery[QUERY_STR_LEN]; + char master_conninfo_stack[MAXCONNINFO]; + char *master_conninfo = &*master_conninfo_stack; + char schema_str[MAXLEN]; + char schema_quoted[MAXLEN]; + int i; /* @@ -196,10 +199,24 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, if (master_conninfo_out != NULL) master_conninfo = master_conninfo_out; + /* + * XXX: This is copied in at least two other procedures + * + * Assemble the unquoted schema name + */ + maxlen_snprintf(schema_str, "repmgr_%s", cluster); + { + char *identifier = PQescapeIdentifier(standby_conn, schema_str, + strlen(schema_str)); + + maxlen_snprintf(schema_quoted, "%s", identifier); + free(identifier); + } + /* find all nodes belonging to this cluster */ - sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes " + sqlquery_snprintf(sqlquery, "SELECT * FROM %s.repl_nodes " " WHERE cluster = '%s' and id <> %d", - cluster, cluster, id); + schema_quoted, cluster, id); res1 = PQexec(standby_conn, sqlquery); if (PQresultStatus(res1) != PGRES_TUPLES_OK) diff --git a/repmgr.c b/repmgr.c index eebf06f6..e1120f72 100644 --- a/repmgr.c +++ b/repmgr.c @@ -316,6 +316,8 @@ do_master_register(void) PGconn *conn; PGresult *res; char sqlquery[QUERY_STR_LEN]; + char schema_str[MAXLEN]; + char schema_quoted[MAXLEN]; bool schema_exists = false; char master_version[MAXVERSIONSTR]; @@ -340,9 +342,20 @@ do_master_register(void) return; } + /* Assemble the unquoted schema name */ + maxlen_snprintf(schema_str, "repmgr_%s", config.cluster_name); + { + char *identifier = PQescapeIdentifier(conn, schema_str, + strlen(schema_str)); + + maxlen_snprintf(schema_quoted, "%s", identifier); + free(identifier); + } + /* Check if there is a schema for this cluster */ - sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace " - "WHERE nspname = 'repmgr_%s'", config.cluster_name); + sqlquery_snprintf(sqlquery, + "SELECT 1 FROM pg_namespace " + "WHERE nspname = '%s'", schema_str); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -357,7 +370,7 @@ do_master_register(void) { if (!force) /* and we are not forcing so error */ { - fprintf(stderr, "Schema repmgr_%s already exists.", config.cluster_name); + fprintf(stderr, "Schema %s already exists.", schema_quoted); PQclear(res); PQfinish(conn); return; @@ -369,20 +382,20 @@ do_master_register(void) if (!schema_exists) { /* ok, create the schema */ - sqlquery_snprintf(sqlquery, "CREATE SCHEMA repmgr_%s", config.cluster_name); + sqlquery_snprintf(sqlquery, "CREATE SCHEMA %s", schema_quoted); if (!PQexec(conn, sqlquery)) { - fprintf(stderr, "Cannot create the schema repmgr_%s: %s\n", - config.cluster_name, PQerrorMessage(conn)); + fprintf(stderr, "Cannot create the schema %s: %s\n", schema_quoted, + PQerrorMessage(conn)); PQfinish(conn); return; } /* ... the tables */ - sqlquery_snprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_nodes ( " + sqlquery_snprintf(sqlquery, "CREATE TABLE %s.repl_nodes ( " " id integer primary key, " " cluster text not null, " - " conninfo text not null)", config.cluster_name); + " conninfo text not null)", schema_quoted); if (!PQexec(conn, sqlquery)) { fprintf(stderr, @@ -391,7 +404,7 @@ do_master_register(void) return; } - sqlquery_snprintf(sqlquery, "CREATE TABLE repmgr_%s.repl_monitor ( " + sqlquery_snprintf(sqlquery, "CREATE TABLE %s.repl_monitor ( " " primary_node INTEGER NOT NULL, " " standby_node INTEGER NOT NULL, " " last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, " @@ -399,7 +412,7 @@ do_master_register(void) " last_wal_standby_location TEXT NOT NULL, " " replication_lag BIGINT NOT NULL, " " apply_lag BIGINT NOT NULL) ", - config.cluster_name); + schema_quoted); } if (!PQexec(conn, sqlquery)) @@ -411,15 +424,17 @@ do_master_register(void) } /* and the view */ - sqlquery_snprintf(sqlquery, "CREATE VIEW repmgr_%s.repl_status AS " + sqlquery_snprintf(sqlquery, "CREATE VIEW %s.repl_status AS " " WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node " " ORDER BY last_monitor_time desc) " - " FROM repmgr_%s.repl_monitor) " + " FROM %s.repl_monitor) " " SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, " " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " " FROM monitor_info a " - " WHERE row_number = 1", config.cluster_name, config.cluster_name); + " WHERE row_number = 1", + schema_quoted, schema_quoted); + if (!PQexec(conn, sqlquery)) { fprintf(stderr, @@ -447,9 +462,9 @@ do_master_register(void) /* Now register the master */ if (force) { - sqlquery_snprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " - " WHERE id = %d", - config.cluster_name, config.node); + sqlquery_snprintf(sqlquery, + "DELETE FROM %s.repl_nodes WHERE id = %d", + schema_quoted, config.node); if (!PQexec(conn, sqlquery)) { @@ -460,9 +475,9 @@ do_master_register(void) } } - sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " + sqlquery_snprintf(sqlquery, "INSERT INTO %s.repl_nodes " "VALUES (%d, '%s', '%s')", - config.cluster_name, config.node, config.cluster_name, + schema_quoted, config.node, config.cluster_name, config.conninfo); if (!PQexec(conn, sqlquery)) @@ -487,12 +502,16 @@ do_standby_register(void) PGresult *res; char sqlquery[QUERY_STR_LEN]; + char schema_str[MAXLEN]; + char schema_quoted[MAXLEN]; char master_version[MAXVERSIONSTR]; char standby_version[MAXVERSIONSTR]; conn = establishDBConnection(config.conninfo, true); + /* XXX: A lot of copied code from do_master_register! Refactor */ + /* should be v9 or better */ pg_version(conn, standby_version); if (strcmp(standby_version, "") == 0) @@ -511,9 +530,20 @@ do_standby_register(void) return; } + /* Assemble the unquoted schema name */ + maxlen_snprintf(schema_str, "repmgr_%s", config.cluster_name); + { + char *identifier = PQescapeIdentifier(conn, schema_str, + strlen(schema_str)); + + maxlen_snprintf(schema_quoted, "%s", identifier); + free(identifier); + } + /* Check if there is a schema for this cluster */ - sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace " - "WHERE nspname = 'repmgr_%s'", config.cluster_name); + sqlquery_snprintf(sqlquery, + "SELECT 1 FROM pg_namespace " + " WHERE nspname = 'repmgr_%s'", schema_str); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -527,7 +557,7 @@ do_standby_register(void) if (PQntuples(res) == 0) /* schema doesn't exists */ { - fprintf(stderr, "Schema repmgr_%s doesn't exists.", config.cluster_name); + fprintf(stderr, "Schema %s doesn't exists.", schema_quoted); PQclear(res); PQfinish(conn); return; @@ -566,9 +596,10 @@ do_standby_register(void) /* Now register the standby */ if (force) { - sqlquery_snprintf(sqlquery, "DELETE FROM repmgr_%s.repl_nodes " + sqlquery_snprintf(sqlquery, + "DELETE FROM %s.repl_nodes " " WHERE id = %d", - config.cluster_name, config.node); + schema_quoted, config.node); if (!PQexec(master_conn, sqlquery)) { @@ -580,9 +611,10 @@ do_standby_register(void) } } - sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " + sqlquery_snprintf(sqlquery, "INSERT INTO %s.repl_nodes " "VALUES (%d, '%s', '%s')", - config.cluster_name, config.node, config.cluster_name, config.conninfo); + schema_quoted, config.node, config.cluster_name, + config.conninfo); if (!PQexec(master_conn, sqlquery)) { From 630d716819ef746a85d115b26f2095ce983ca628 Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Mon, 7 Feb 2011 01:48:14 -0800 Subject: [PATCH 29/34] Use the proper freeing method As according to http://www.postgresql.org/docs/9.0/static/libpq-exec.html#LIBPQ-EXEC-ESCAPE-STRING Signed-off-by: Dan Farina --- dbutils.c | 2 +- repmgr.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dbutils.c b/dbutils.c index 5cc82397..9756aa2d 100644 --- a/dbutils.c +++ b/dbutils.c @@ -210,7 +210,7 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, strlen(schema_str)); maxlen_snprintf(schema_quoted, "%s", identifier); - free(identifier); + PQfreemem(identifier); } /* find all nodes belonging to this cluster */ diff --git a/repmgr.c b/repmgr.c index e1120f72..45626bbe 100644 --- a/repmgr.c +++ b/repmgr.c @@ -349,7 +349,7 @@ do_master_register(void) strlen(schema_str)); maxlen_snprintf(schema_quoted, "%s", identifier); - free(identifier); + PQfreemem(identifier); } /* Check if there is a schema for this cluster */ @@ -537,7 +537,7 @@ do_standby_register(void) strlen(schema_str)); maxlen_snprintf(schema_quoted, "%s", identifier); - free(identifier); + PQfreemem(identifier); } /* Check if there is a schema for this cluster */ From ebbb7c3a476642b3a42394e1aa54676ed438b8ee Mon Sep 17 00:00:00 2001 From: Dan Farina Date: Mon, 7 Feb 2011 02:26:02 -0800 Subject: [PATCH 30/34] Fix more quoting: used an overly-quoted copy Signed-off-by: Dan Farina --- repmgr.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/repmgr.c b/repmgr.c index 45626bbe..1b519d1e 100644 --- a/repmgr.c +++ b/repmgr.c @@ -543,7 +543,7 @@ do_standby_register(void) /* Check if there is a schema for this cluster */ sqlquery_snprintf(sqlquery, "SELECT 1 FROM pg_namespace " - " WHERE nspname = 'repmgr_%s'", schema_str); + " WHERE nspname = '%s'", schema_str); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -555,9 +555,10 @@ do_standby_register(void) return; } - if (PQntuples(res) == 0) /* schema doesn't exists */ + /* schema doesn't exist */ + if (PQntuples(res) == 0) { - fprintf(stderr, "Schema %s doesn't exists.", schema_quoted); + fprintf(stderr, "Schema %s doesn't exist.\n", schema_quoted); PQclear(res); PQfinish(conn); return; From da82829659a2f4ce6deaa7affecef913dfc01e59 Mon Sep 17 00:00:00 2001 From: Daniel Farina Date: Thu, 10 Feb 2011 02:10:58 -0800 Subject: [PATCH 31/34] Avoid checking config file when performing standby clone action Signed-off-by: Daniel Farina --- repmgr.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/repmgr.c b/repmgr.c index 1b519d1e..1d22cf66 100644 --- a/repmgr.c +++ b/repmgr.c @@ -262,16 +262,21 @@ main(int argc, char **argv) else dbname = "postgres"; } - + /* - * Read the configuration file: repmgr.conf + * Read the configuration file: repmgr.conf, but only if we're not doing a + * STANDBY CLONE action: it is not necessary to have the configuration file + * in that case. */ - parse_config(config_file, &config); - if (config.node == -1) + if (action != STANDBY_CLONE) { - fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); - exit(1); + parse_config(config_file, &config); + if (config.node == -1) + { + fprintf(stderr, "Node information is missing. " + "Check the configuration file.\n"); + exit(1); + } } keywords[2] = "user"; From 4b007bf4bcb16e81db75b5ad50134c4ab9728cfb Mon Sep 17 00:00:00 2001 From: Daniel Farina Date: Thu, 10 Feb 2011 03:12:51 -0800 Subject: [PATCH 32/34] Use a better check for when to issue an error message This patch changes raising the error "You need to use connection parameters to the master when issuing a STANDBY CLONE command." to only occur when no host (a global variable, that is abused for at least two purposes, but is okay in this case) is passed, rather than when no config file is passed, which is fine for standby clone (which itself is a wrapper for rsync) Signed-off-by: Daniel Farina --- repmgr.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/repmgr.c b/repmgr.c index 1d22cf66..127043ff 100644 --- a/repmgr.c +++ b/repmgr.c @@ -1557,19 +1557,20 @@ check_parameters_for_action(const int action) ok = false; } break; - case STANDBY_CLONE: - /* - * To clone a master into a standby we need connection parameters - * repmgr.conf is useless because we don't have a server running - * in the standby - */ - if (config_file != NULL) - { - fprintf(stderr, "\nYou need to use connection parameters to the master when issuing a STANDBY CLONE command."); + case STANDBY_CLONE: + /* + * To clone a master into a standby we need connection parameters + * repmgr.conf is useless because we don't have a server running in + * the standby; warn the user, but keep going. + */ + if (host == NULL) + { + fprintf(stderr, "\nYou need to use connection parameters to " + "the master when issuing a STANDBY CLONE command."); fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); - ok = false; - } + ok = false; + } break; } From ce212914188fb07ef1b3efa64dd18ca36b1488b8 Mon Sep 17 00:00:00 2001 From: Daniel Farina Date: Thu, 10 Feb 2011 03:17:10 -0800 Subject: [PATCH 33/34] Issue a message when a configuration file is passed unnecessarily Simply intends to set expectations around the fact that a config file is not used *and* doesn't affect anything material about the standby clone command. This uses a notion of "logging level" (like NOTICE) that is not yet seen this program, but I'll probably introduce that soon. Signed-off-by: Daniel Farina --- repmgr.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/repmgr.c b/repmgr.c index 127043ff..cfee11af 100644 --- a/repmgr.c +++ b/repmgr.c @@ -1558,6 +1558,16 @@ check_parameters_for_action(const int action) } break; case STANDBY_CLONE: + /* + * Issue a friendly notice that the configuration file is not + * necessary nor read at all in when performing a STANDBY CLONE + * action. + */ + if (config_file != NULL) + fprintf(stderr, "NOTICE: The passed configuration file is not " + "required nor used when performing the STANDBY CLONE " + "command.\n"); + /* * To clone a master into a standby we need connection parameters * repmgr.conf is useless because we don't have a server running in From 3ef1fa126d9c9b9ba3b29deab7f67218cdf7ce10 Mon Sep 17 00:00:00 2001 From: Greg Smith Date: Mon, 14 Feb 2011 21:51:14 -0500 Subject: [PATCH 34/34] astyle run against Heroku code --- config.c | 7 +- dbutils.c | 36 ++-- dbutils.h | 4 +- repmgr.c | 484 +++++++++++++++++++++++++++--------------------------- repmgrd.c | 60 +++---- 5 files changed, 296 insertions(+), 295 deletions(-) diff --git a/config.c b/config.c index 868ec72a..cd0962e6 100644 --- a/config.c +++ b/config.c @@ -30,17 +30,18 @@ parse_config(const char *config_file, repmgr_config *config) FILE *fp = fopen (config_file, "r"); - if (fp == NULL) { + if (fp == NULL) + { fprintf(stderr, _("Could not find configuration file '%s'\n"), config_file); exit(1); } - + /* Initialize */ memset(config->cluster_name, 0, sizeof(config->cluster_name)); config->node = -1; memset(config->conninfo, 0, sizeof(config->conninfo)); memset(config->rsync_options, 0, sizeof(config->rsync_options)); - + /* Read next line */ while ((s = fgets (buff, sizeof buff, fp)) != NULL) { diff --git a/dbutils.c b/dbutils.c index 9756aa2d..deeb1b30 100644 --- a/dbutils.c +++ b/dbutils.c @@ -31,7 +31,7 @@ establishDBConnection(const char *conninfo, const bool exit_on_error) if ((PQstatus(conn) != CONNECTION_OK)) { fprintf(stderr, "Connection to database failed: %s", - PQerrorMessage(conn)); + PQerrorMessage(conn)); if (exit_on_error) { @@ -83,10 +83,10 @@ pg_version(PGconn *conn, char* major_version) char *major_version2; res = PQexec(conn, - "WITH pg_version(ver) AS " - "(SELECT split_part(version(), ' ', 2)) " - "SELECT split_part(ver, '.', 1), split_part(ver, '.', 2) " - "FROM pg_version"); + "WITH pg_version(ver) AS " + "(SELECT split_part(version(), ' ', 2)) " + "SELECT split_part(ver, '.', 1), split_part(ver, '.', 2) " + "FROM pg_version"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -103,7 +103,7 @@ pg_version(PGconn *conn, char* major_version) { /* form a major version string */ xsnprintf(major_version, MAXVERSIONSTR, "%d.%s", major_version1, - major_version2); + major_version2); } else strcpy(major_version, ""); @@ -116,14 +116,14 @@ pg_version(PGconn *conn, char* major_version) bool guc_setted(PGconn *conn, const char *parameter, const char *op, - const char *value) + const char *value) { PGresult *res; char sqlquery[QUERY_STR_LEN]; sqlquery_snprintf(sqlquery, "SELECT true FROM pg_settings " - " WHERE name = '%s' AND setting %s '%s'", - parameter, op, value); + " WHERE name = '%s' AND setting %s '%s'", + parameter, op, value); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -152,9 +152,9 @@ get_cluster_size(PGconn *conn) char sqlquery[QUERY_STR_LEN]; sqlquery_snprintf( - sqlquery, - "SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) " - " FROM pg_database "); + sqlquery, + "SELECT pg_size_pretty(SUM(pg_database_size(oid))::bigint) " + " FROM pg_database "); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -179,7 +179,7 @@ get_cluster_size(PGconn *conn) */ PGconn * getMasterConnection(PGconn *standby_conn, int id, char *cluster, - int *master_id, char *master_conninfo_out) + int *master_id, char *master_conninfo_out) { PGconn *master_conn = NULL; PGresult *res1; @@ -207,7 +207,7 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, maxlen_snprintf(schema_str, "repmgr_%s", cluster); { char *identifier = PQescapeIdentifier(standby_conn, schema_str, - strlen(schema_str)); + strlen(schema_str)); maxlen_snprintf(schema_quoted, "%s", identifier); PQfreemem(identifier); @@ -215,14 +215,14 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, /* find all nodes belonging to this cluster */ sqlquery_snprintf(sqlquery, "SELECT * FROM %s.repl_nodes " - " WHERE cluster = '%s' and id <> %d", - schema_quoted, cluster, id); + " WHERE cluster = '%s' and id <> %d", + schema_quoted, cluster, id); res1 = PQexec(standby_conn, sqlquery); if (PQresultStatus(res1) != PGRES_TUPLES_OK) { fprintf(stderr, "Can't get nodes info: %s\n", - PQerrorMessage(standby_conn)); + PQerrorMessage(standby_conn)); PQclear(res1); PQfinish(standby_conn); exit(1); @@ -248,7 +248,7 @@ getMasterConnection(PGconn *standby_conn, int id, char *cluster, if (PQresultStatus(res2) != PGRES_TUPLES_OK) { fprintf(stderr, "Can't get recovery state from this node: %s\n", - PQerrorMessage(master_conn)); + PQerrorMessage(master_conn)); PQclear(res2); PQfinish(master_conn); continue; diff --git a/dbutils.h b/dbutils.h index 4aa28c9b..4e389fb0 100644 --- a/dbutils.h +++ b/dbutils.h @@ -21,7 +21,7 @@ PGconn *establishDBConnection(const char *conninfo, const bool exit_on_error); bool is_standby(PGconn *conn); char *pg_version(PGconn *conn, char* major_version); bool guc_setted(PGconn *conn, const char *parameter, const char *op, - const char *value); + const char *value); const char *get_cluster_size(PGconn *conn); PGconn *getMasterConnection(PGconn *standby_conn, int id, char *cluster, - int *master_id, char *master_conninfo_out); + int *master_id, char *master_conninfo_out); diff --git a/repmgr.c b/repmgr.c index cfee11af..993ceb1c 100644 --- a/repmgr.c +++ b/repmgr.c @@ -47,7 +47,7 @@ static void help(const char *progname); static bool create_recovery_file(const char *data_dir, char *master_conninfo); static int copy_remote_files(char *host, char *remote_user, char *remote_path, - char *local_path, bool is_directory); + char *local_path, bool is_directory); static bool check_parameters_for_action(const int action); static void do_master_register(void); @@ -119,7 +119,7 @@ main(int argc, char **argv) while ((c = getopt_long(argc, argv, "d:h:p:U:D:f:R:w:F:v", long_options, - &optindex)) != -1) + &optindex)) != -1) { switch (c) { @@ -130,20 +130,20 @@ main(int argc, char **argv) host = optarg; break; case 'p': - masterport = optarg; - break; + masterport = optarg; + break; case 'U': username = optarg; break; case 'D': dest_dir = optarg; - break; + break; case 'f': config_file = optarg; - break; + break; case 'R': remote_user = optarg; - break; + break; case 'w': wal_keep_segments = optarg; break; @@ -154,8 +154,8 @@ main(int argc, char **argv) verbose = true; break; default: - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); } } @@ -172,10 +172,10 @@ main(int argc, char **argv) { server_mode = argv[optind++]; if (strcasecmp(server_mode, "STANDBY") != 0 && - strcasecmp(server_mode, "MASTER") != 0) + strcasecmp(server_mode, "MASTER") != 0) { fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + progname); exit(1); } } @@ -205,7 +205,7 @@ main(int argc, char **argv) else { fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + progname); exit(1); } } @@ -231,8 +231,8 @@ main(int argc, char **argv) default: fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind + 1]); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); } @@ -274,7 +274,7 @@ main(int argc, char **argv) if (config.node == -1) { fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); + "Check the configuration file.\n"); exit(1); } } @@ -306,8 +306,8 @@ main(int argc, char **argv) do_standby_follow(); break; default: - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); } @@ -335,7 +335,7 @@ do_master_register(void) { PQfinish(conn); fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), - progname); + progname); return; } @@ -351,7 +351,7 @@ do_master_register(void) maxlen_snprintf(schema_str, "repmgr_%s", config.cluster_name); { char *identifier = PQescapeIdentifier(conn, schema_str, - strlen(schema_str)); + strlen(schema_str)); maxlen_snprintf(schema_quoted, "%s", identifier); PQfreemem(identifier); @@ -359,13 +359,13 @@ do_master_register(void) /* Check if there is a schema for this cluster */ sqlquery_snprintf(sqlquery, - "SELECT 1 FROM pg_namespace " - "WHERE nspname = '%s'", schema_str); + "SELECT 1 FROM pg_namespace " + "WHERE nspname = '%s'", schema_str); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Can't get info about schemas: %s\n", - PQerrorMessage(conn)); + PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return; @@ -391,59 +391,59 @@ do_master_register(void) if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot create the schema %s: %s\n", schema_quoted, - PQerrorMessage(conn)); + PQerrorMessage(conn)); PQfinish(conn); return; } /* ... the tables */ sqlquery_snprintf(sqlquery, "CREATE TABLE %s.repl_nodes ( " - " id integer primary key, " - " cluster text not null, " - " conninfo text not null)", schema_quoted); + " id integer primary key, " + " cluster text not null, " + " conninfo text not null)", schema_quoted); if (!PQexec(conn, sqlquery)) { fprintf(stderr, - config.cluster_name, PQerrorMessage(conn)); + config.cluster_name, PQerrorMessage(conn)); PQfinish(conn); return; } sqlquery_snprintf(sqlquery, "CREATE TABLE %s.repl_monitor ( " - " primary_node INTEGER NOT NULL, " - " standby_node INTEGER NOT NULL, " - " last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, " - " last_wal_primary_location TEXT NOT NULL, " - " last_wal_standby_location TEXT NOT NULL, " - " replication_lag BIGINT NOT NULL, " - " apply_lag BIGINT NOT NULL) ", - schema_quoted); + " primary_node INTEGER NOT NULL, " + " standby_node INTEGER NOT NULL, " + " last_monitor_time TIMESTAMP WITH TIME ZONE NOT NULL, " + " last_wal_primary_location TEXT NOT NULL, " + " last_wal_standby_location TEXT NOT NULL, " + " replication_lag BIGINT NOT NULL, " + " apply_lag BIGINT NOT NULL) ", + schema_quoted); } if (!PQexec(conn, sqlquery)) { fprintf(stderr, - config.cluster_name, PQerrorMessage(conn)); + config.cluster_name, PQerrorMessage(conn)); PQfinish(conn); return; } /* and the view */ sqlquery_snprintf(sqlquery, "CREATE VIEW %s.repl_status AS " - " WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node " - " ORDER BY last_monitor_time desc) " - " FROM %s.repl_monitor) " - " SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, " - " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " - " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " - " FROM monitor_info a " - " WHERE row_number = 1", - schema_quoted, schema_quoted); + " WITH monitor_info AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY primary_node, standby_node " + " ORDER BY last_monitor_time desc) " + " FROM %s.repl_monitor) " + " SELECT primary_node, standby_node, last_monitor_time, last_wal_primary_location, " + " last_wal_standby_location, pg_size_pretty(replication_lag) replication_lag, " + " pg_size_pretty(apply_lag) apply_lag, age(now(), last_monitor_time) AS time_lag " + " FROM monitor_info a " + " WHERE row_number = 1", + schema_quoted, schema_quoted); if (!PQexec(conn, sqlquery)) { fprintf(stderr, - config.cluster_name, PQerrorMessage(conn)); + config.cluster_name, PQerrorMessage(conn)); PQfinish(conn); return; } @@ -454,7 +454,7 @@ do_master_register(void) /* Ensure there isn't any other master already registered */ master_conn = getMasterConnection(conn, config.node, - config.cluster_name, &id, NULL); + config.cluster_name, &id, NULL); if (master_conn != NULL) { @@ -468,27 +468,27 @@ do_master_register(void) if (force) { sqlquery_snprintf(sqlquery, - "DELETE FROM %s.repl_nodes WHERE id = %d", - schema_quoted, config.node); + "DELETE FROM %s.repl_nodes WHERE id = %d", + schema_quoted, config.node); if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot delete node details, %s\n", - PQerrorMessage(conn)); + PQerrorMessage(conn)); PQfinish(conn); return; } } sqlquery_snprintf(sqlquery, "INSERT INTO %s.repl_nodes " - "VALUES (%d, '%s', '%s')", - schema_quoted, config.node, config.cluster_name, - config.conninfo); + "VALUES (%d, '%s', '%s')", + schema_quoted, config.node, config.cluster_name, + config.conninfo); if (!PQexec(conn, sqlquery)) { fprintf(stderr, "Cannot insert node details, %s\n", - PQerrorMessage(conn)); + PQerrorMessage(conn)); PQfinish(conn); return; } @@ -523,7 +523,7 @@ do_standby_register(void) { PQfinish(conn); fprintf(stderr, _("%s needs standby to be PostgreSQL 9.0 or better\n"), - progname); + progname); return; } @@ -539,7 +539,7 @@ do_standby_register(void) maxlen_snprintf(schema_str, "repmgr_%s", config.cluster_name); { char *identifier = PQescapeIdentifier(conn, schema_str, - strlen(schema_str)); + strlen(schema_str)); maxlen_snprintf(schema_quoted, "%s", identifier); PQfreemem(identifier); @@ -547,14 +547,14 @@ do_standby_register(void) /* Check if there is a schema for this cluster */ sqlquery_snprintf(sqlquery, - "SELECT 1 FROM pg_namespace " - " WHERE nspname = '%s'", schema_str); + "SELECT 1 FROM pg_namespace " + " WHERE nspname = '%s'", schema_str); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Can't get info about tablespaces: %s\n", - PQerrorMessage(conn)); + PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return; @@ -572,7 +572,7 @@ do_standby_register(void) /* check if there is a master in this cluster */ master_conn = getMasterConnection(conn, config.node, config.cluster_name, - &master_id, NULL); + &master_id, NULL); if (!master_conn) return; @@ -584,7 +584,7 @@ do_standby_register(void) PQfinish(conn); PQfinish(master_conn); fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), - progname); + progname); return; } @@ -594,7 +594,7 @@ do_standby_register(void) PQfinish(conn); PQfinish(master_conn); fprintf(stderr, _("%s needs versions of both master (%s) and standby (%s) to match.\n"), - progname, master_version, standby_version); + progname, master_version, standby_version); return; } @@ -603,14 +603,14 @@ do_standby_register(void) if (force) { sqlquery_snprintf(sqlquery, - "DELETE FROM %s.repl_nodes " - " WHERE id = %d", - schema_quoted, config.node); + "DELETE FROM %s.repl_nodes " + " WHERE id = %d", + schema_quoted, config.node); if (!PQexec(master_conn, sqlquery)) { fprintf(stderr, "Cannot delete node details, %s\n", - PQerrorMessage(master_conn)); + PQerrorMessage(master_conn)); PQfinish(master_conn); PQfinish(conn); return; @@ -618,14 +618,14 @@ do_standby_register(void) } sqlquery_snprintf(sqlquery, "INSERT INTO %s.repl_nodes " - "VALUES (%d, '%s', '%s')", - schema_quoted, config.node, config.cluster_name, - config.conninfo); + "VALUES (%d, '%s', '%s')", + schema_quoted, config.node, config.cluster_name, + config.conninfo); if (!PQexec(master_conn, sqlquery)) { fprintf(stderr, "Cannot insert node details, %s\n", - PQerrorMessage(master_conn)); + PQerrorMessage(master_conn)); PQfinish(master_conn); PQfinish(conn); return; @@ -670,46 +670,46 @@ do_standby_clone(void) /* Check this directory could be used as a PGDATA dir */ switch (check_dir(dest_dir)) { - case 0: - /* dest_dir not there, must create it */ + case 0: + /* dest_dir not there, must create it */ if (verbose) - printf(_("creating directory %s ... "), dest_dir); - fflush(stdout); + printf(_("creating directory %s ... "), dest_dir); + fflush(stdout); - if (!create_directory(dest_dir)) + if (!create_directory(dest_dir)) { - fprintf(stderr, _("%s: couldn't create directory %s ... "), + fprintf(stderr, _("%s: couldn't create directory %s ... "), progname, dest_dir); return; } - break; - case 1: - /* Present but empty, fix permissions and use it */ + break; + case 1: + /* Present but empty, fix permissions and use it */ if (verbose) - printf(_("fixing permissions on existing directory %s ... "), - dest_dir); - fflush(stdout); + printf(_("fixing permissions on existing directory %s ... "), + dest_dir); + fflush(stdout); if (!set_directory_permissions(dest_dir)) - { - fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), - progname, dest_dir, strerror(errno)); + { + fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), + progname, dest_dir, strerror(errno)); return; - } - break; - case 2: - /* Present and not empty */ - fprintf(stderr, - _("%s: directory \"%s\" exists but is not empty\n"), - progname, dest_dir); + } + break; + case 2: + /* Present and not empty */ + fprintf(stderr, + _("%s: directory \"%s\" exists but is not empty\n"), + progname, dest_dir); - pg_dir = is_pg_dir(dest_dir); - if (pg_dir && !force) + pg_dir = is_pg_dir(dest_dir); + if (pg_dir && !force) { fprintf(stderr, _("\nThis looks like a PostgreSQL directroy.\n" - "If you are sure you want to clone here, " - "please check there is no PostgreSQL server " - "running and use the --force option\n")); + "If you are sure you want to clone here, " + "please check there is no PostgreSQL server " + "running and use the --force option\n")); return; } else if (pg_dir && force) @@ -717,12 +717,12 @@ do_standby_clone(void) /* Let it continue */ break; } - else + else return; - default: - /* Trouble accessing directory */ - fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"), - progname, dest_dir, strerror(errno)); + default: + /* Trouble accessing directory */ + fprintf(stderr, _("%s: could not access directory \"%s\": %s\n"), + progname, dest_dir, strerror(errno)); } /* Connection parameters for master only */ @@ -736,7 +736,7 @@ do_standby_clone(void) if (!conn) { fprintf(stderr, _("%s: could not connect to master\n"), - progname); + progname); return; } @@ -746,7 +746,7 @@ do_standby_clone(void) { PQfinish(conn); fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), - progname); + progname); return; } @@ -785,9 +785,9 @@ do_standby_clone(void) * Check if the tablespace locations exists and that we can write to them. */ sqlquery_snprintf(sqlquery, - "SELECT spclocation " - " FROM pg_tablespace " - "WHERE spcname NOT IN ('pg_default', 'pg_global')"); + "SELECT spclocation " + " FROM pg_tablespace " + "WHERE spcname NOT IN ('pg_default', 'pg_global')"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -804,58 +804,58 @@ do_standby_clone(void) /* Check this directory could be used as a PGDATA dir */ switch (check_dir(tblspc_dir)) { - case 0: - /* tblspc_dir not there, must create it */ + case 0: + /* tblspc_dir not there, must create it */ if (verbose) - printf(_("creating directory \"%s\"... "), tblspc_dir); - fflush(stdout); + printf(_("creating directory \"%s\"... "), tblspc_dir); + fflush(stdout); - if (!create_directory(tblspc_dir)) + if (!create_directory(tblspc_dir)) { - fprintf(stderr, - _("%s: couldn't create directory \"%s\"... "), + fprintf(stderr, + _("%s: couldn't create directory \"%s\"... "), progname, tblspc_dir); PQclear(res); PQfinish(conn); return; } - break; - case 1: - /* Present but empty, fix permissions and use it */ + break; + case 1: + /* Present but empty, fix permissions and use it */ if (verbose) - printf(_("fixing permissions on existing directory \"%s\"... "), - tblspc_dir); - fflush(stdout); + printf(_("fixing permissions on existing directory \"%s\"... "), + tblspc_dir); + fflush(stdout); - if (!set_directory_permissions(tblspc_dir)) - { - fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), - progname, tblspc_dir, strerror(errno)); + if (!set_directory_permissions(tblspc_dir)) + { + fprintf(stderr, _("%s: could not change permissions of directory \"%s\": %s\n"), + progname, tblspc_dir, strerror(errno)); PQclear(res); PQfinish(conn); return; - } - break; - case 2: - /* Present and not empty */ - if (!force) - { - fprintf( - stderr, - _("%s: directory \"%s\" exists but is not empty\n"), - progname, tblspc_dir); - PQclear(res); - PQfinish(conn); - return; - } - default: - /* Trouble accessing directory */ - fprintf(stderr, - _("%s: could not access directory \"%s\": %s\n"), - progname, tblspc_dir, strerror(errno)); + } + break; + case 2: + /* Present and not empty */ + if (!force) + { + fprintf( + stderr, + _("%s: directory \"%s\" exists but is not empty\n"), + progname, tblspc_dir); PQclear(res); PQfinish(conn); return; + } + default: + /* Trouble accessing directory */ + fprintf(stderr, + _("%s: could not access directory \"%s\": %s\n"), + progname, tblspc_dir, strerror(errno)); + PQclear(res); + PQfinish(conn); + return; } } @@ -863,11 +863,11 @@ do_standby_clone(void) /* Get the data directory full path and the configuration files location */ sqlquery_snprintf( - sqlquery, - "SELECT name, setting " - " FROM pg_settings " - " WHERE name IN ('data_directory', 'config_file', 'hba_file', " - " 'ident_file')"); + sqlquery, + "SELECT name, setting " + " FROM pg_settings " + " WHERE name IN ('data_directory', 'config_file', 'hba_file', " + " 'ident_file')"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -896,9 +896,9 @@ do_standby_clone(void) * so we can say to the user we need those files */ sqlquery_snprintf( - sqlquery, - "SELECT pg_xlogfile_name(pg_start_backup('repmgr_standby_clone_%ld'))", - time(NULL)); + sqlquery, + "SELECT pg_xlogfile_name(pg_start_backup('repmgr_standby_clone_%ld'))", + time(NULL)); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -935,22 +935,22 @@ do_standby_clone(void) /* need to create the global sub directory */ maxlen_snprintf(master_control_file, "%s/global/pg_control", - master_data_directory); + master_data_directory); maxlen_snprintf(local_control_file, "%s/global", dest_dir); if (!create_directory(local_control_file)) { fprintf(stderr, _("%s: couldn't create directory %s ... "), - progname, dest_dir); + progname, dest_dir); goto stop_backup; } r = copy_remote_files(host, remote_user, master_control_file, - local_control_file, false); + local_control_file, false); if (r != 0) goto stop_backup; r = copy_remote_files(host, remote_user, master_data_directory, dest_dir, - true); + true); if (r != 0) goto stop_backup; @@ -960,27 +960,27 @@ do_standby_clone(void) * these rsync happen concurrently */ sqlquery_snprintf(sqlquery, - "SELECT spclocation " - " FROM pg_tablespace " - " WHERE spcname NOT IN ('pg_default', 'pg_global')"); + "SELECT spclocation " + " FROM pg_tablespace " + " WHERE spcname NOT IN ('pg_default', 'pg_global')"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Can't get info about tablespaces: %s\n", - PQerrorMessage(conn)); + PQerrorMessage(conn)); PQclear(res); goto stop_backup; } for (i = 0; i < PQntuples(res); i++) { r = copy_remote_files(host, remote_user, PQgetvalue(res, i, 0), - PQgetvalue(res, i, 0), true); + PQgetvalue(res, i, 0), true); if (r != 0) goto stop_backup; } r = copy_remote_files(host, remote_user, master_config_file, dest_dir, - false); + false); if (r != 0) goto stop_backup; @@ -989,7 +989,7 @@ do_standby_clone(void) goto stop_backup; r = copy_remote_files(host, remote_user, master_ident_file, dest_dir, - false); + false); if (r != 0) goto stop_backup; @@ -999,7 +999,7 @@ stop_backup: if (!conn) { fprintf(stderr, _("%s: could not connect to master\n"), - progname); + progname); return; } @@ -1019,8 +1019,8 @@ stop_backup: if (verbose) { printf( - _("%s requires primary to keep WAL files %s until at least %s\n"), - progname, first_wal_segment, last_wal_segment); + _("%s requires primary to keep WAL files %s until at least %s\n"), + progname, first_wal_segment, last_wal_segment); /* * Only free the first_wal_segment since it was copied out of the @@ -1045,7 +1045,7 @@ stop_backup: if (!create_directory(local_control_file)) { fprintf(stderr, _("%s: couldn't create directory %s, you will need to do it manually...\n"), - progname, dest_dir); + progname, dest_dir); } /* Finally, write the recovery.conf file */ @@ -1086,7 +1086,7 @@ do_standby_promote(void) { PQfinish(conn); fprintf(stderr, _("%s needs standby to be PostgreSQL 9.0 or better\n"), - progname); + progname); return; } @@ -1094,13 +1094,13 @@ do_standby_promote(void) if (!is_standby(conn)) { fprintf(stderr, - "repmgr: The command should be executed in a standby node\n"); + "repmgr: The command should be executed in a standby node\n"); return; } /* we also need to check if there isn't any master already */ old_master_conn = getMasterConnection(conn, config.node, config.cluster_name, - &old_master_id, NULL); + &old_master_id, NULL); if (old_master_conn != NULL) { @@ -1114,12 +1114,12 @@ do_standby_promote(void) /* Get the data directory full path and the last subdirectory */ sqlquery_snprintf(sqlquery, "SELECT setting " - " FROM pg_settings WHERE name = 'data_directory'"); + " FROM pg_settings WHERE name = 'data_directory'"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Can't get info about data directory: %s\n", - PQerrorMessage(conn)); + PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return; @@ -1197,7 +1197,7 @@ do_standby_follow(void) /* we also need to check if there is any master in the cluster */ master_conn = getMasterConnection(conn, config.node, config.cluster_name, - &master_id, (char *) &master_conninfo); + &master_id, (char *) &master_conninfo); if (master_conn == NULL) { @@ -1211,7 +1211,7 @@ do_standby_follow(void) { PQfinish(conn); fprintf(stderr, "%s: The node to follow should be a master\n", - progname); + progname); return; } @@ -1222,7 +1222,7 @@ do_standby_follow(void) PQfinish(conn); PQfinish(master_conn); fprintf(stderr, _("%s needs master to be PostgreSQL 9.0 or better\n"), - progname); + progname); return; } @@ -1232,7 +1232,7 @@ do_standby_follow(void) PQfinish(conn); PQfinish(master_conn); fprintf(stderr, _("%s needs versions of both master (%s) and standby (%s) to match.\n"), - progname, master_version, standby_version); + progname, master_version, standby_version); return; } @@ -1263,12 +1263,12 @@ do_standby_follow(void) /* Get the data directory full path */ sqlquery_snprintf(sqlquery, "SELECT setting " - " FROM pg_settings WHERE name = 'data_directory'"); + " FROM pg_settings WHERE name = 'data_directory'"); res = PQexec(conn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "Can't get info about data directory: %s\n", - PQerrorMessage(conn)); + PQerrorMessage(conn)); PQclear(res); PQfinish(conn); return; @@ -1302,7 +1302,7 @@ help(const char *progname) printf(_("Usage:\n")); printf(_(" %s [OPTIONS] master {register}\n"), progname); printf(_(" %s [OPTIONS] standby {register|clone|promote|follow}\n"), - progname); + progname); printf(_("\nGeneral options:\n")); printf(_(" --help show this help, then exit\n")); printf(_(" --version output version information, then exit\n")); @@ -1375,15 +1375,15 @@ create_recovery_file(const char *data_dir, char *master_conninfo) if (password == NULL) { fprintf(stderr, - _("%s: Panic! PGPASSWORD not set, how can we get here?\n"), - progname); + _("%s: Panic! PGPASSWORD not set, how can we get here?\n"), + progname); exit(255); } maxlen_snprintf(line, - "primary_conninfo = 'host=%s port=%s password=%s'\n", - host, ((masterport==NULL) ? "5432" : masterport), - password); + "primary_conninfo = 'host=%s port=%s password=%s'\n", + host, ((masterport==NULL) ? "5432" : masterport), + password); } else maxlen_snprintf(line, "primary_conninfo = '%s'\n", master_conninfo); @@ -1404,7 +1404,7 @@ create_recovery_file(const char *data_dir, char *master_conninfo) static int 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[MAXLEN]; char options[MAXLEN]; @@ -1413,8 +1413,8 @@ copy_remote_files(char *host, char *remote_user, char *remote_path, if (strnlen(config.rsync_options, MAXLEN) == 0) maxlen_snprintf( - options, "%s", - "--archive --checksum --compress --progress --rsh=ssh"); + options, "%s", + "--archive --checksum --compress --progress --rsh=ssh"); else maxlen_snprintf(options, "%s", config.rsync_options); @@ -1433,14 +1433,14 @@ copy_remote_files(char *host, char *remote_user, char *remote_path, if (is_directory) { strcat(options, - " --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid"); + " --exclude=pg_xlog* --exclude=pg_control --exclude=*.pid"); maxlen_snprintf(script, "rsync %s %s:%s/* %s", - options, host_string, remote_path, local_path); + options, host_string, remote_path, local_path); } else { maxlen_snprintf(script, "rsync %s %s:%s %s/.", - options, host_string, remote_path, local_path); + options, host_string, remote_path, local_path); } if (verbose) @@ -1450,8 +1450,8 @@ copy_remote_files(char *host, char *remote_user, char *remote_path, if (r != 0) fprintf(stderr, - _("Can't rsync from remote file or directory (%s:%s)\n"), - host_string, remote_path); + _("Can't rsync from remote file or directory (%s:%s)\n"), + host_string, remote_path); return r; } @@ -1473,19 +1473,19 @@ check_parameters_for_action(const int action) * all other parameters are at least useless and could be * confusing so reject them */ - if ((host != NULL) || (masterport != NULL) || - (username != NULL) || (dbname != NULL)) + if ((host != NULL) || (masterport != NULL) || + (username != NULL) || (dbname != NULL)) { fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a MASTER REGISTER command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; - } + } if (dest_dir != NULL) { fprintf(stderr, "\nYou don't need a destination directory for MASTER REGISTER command"); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; } break; @@ -1495,19 +1495,19 @@ check_parameters_for_action(const int action) * we don't need connection parameters to the master * because we can detect the master in repl_nodes */ - if ((host != NULL) || (masterport != NULL) || - (username != NULL) || (dbname != NULL)) + if ((host != NULL) || (masterport != NULL) || + (username != NULL) || (dbname != NULL)) { fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY REGISTER command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; - } + } if (dest_dir != NULL) { fprintf(stderr, "\nYou don't need a destination directory for STANDBY REGISTER command"); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; } break; @@ -1518,19 +1518,19 @@ check_parameters_for_action(const int action) * because we will try to detect the master in repl_nodes * if we can't find it then the promote action will be cancelled */ - if ((host != NULL) || (masterport != NULL) || - (username != NULL) || (dbname != NULL)) + if ((host != NULL) || (masterport != NULL) || + (username != NULL) || (dbname != NULL)) { fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY PROMOTE command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; - } + } if (dest_dir != NULL) { fprintf(stderr, "\nYou don't need a destination directory for STANDBY PROMOTE command"); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; } break; @@ -1541,46 +1541,46 @@ check_parameters_for_action(const int action) * because we will try to detect the master in repl_nodes * if we can't find it then the follow action will be cancelled */ - if ((host != NULL) || (masterport != NULL) || - (username != NULL) || (dbname != NULL)) + if ((host != NULL) || (masterport != NULL) || + (username != NULL) || (dbname != NULL)) { fprintf(stderr, "\nYou can't use connection parameters to the master when issuing a STANDBY FOLLOW command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; - } + } if (dest_dir != NULL) { fprintf(stderr, "\nYou don't need a destination directory for STANDBY FOLLOW command"); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); ok = false; } break; - case STANDBY_CLONE: - /* - * Issue a friendly notice that the configuration file is not - * necessary nor read at all in when performing a STANDBY CLONE - * action. - */ - if (config_file != NULL) - fprintf(stderr, "NOTICE: The passed configuration file is not " - "required nor used when performing the STANDBY CLONE " - "command.\n"); + case STANDBY_CLONE: + /* + * Issue a friendly notice that the configuration file is not + * necessary nor read at all in when performing a STANDBY CLONE + * action. + */ + if (config_file != NULL) + fprintf(stderr, "NOTICE: The passed configuration file is not " + "required nor used when performing the STANDBY CLONE " + "command.\n"); - /* - * To clone a master into a standby we need connection parameters - * repmgr.conf is useless because we don't have a server running in - * the standby; warn the user, but keep going. - */ - if (host == NULL) - { - fprintf(stderr, "\nYou need to use connection parameters to " - "the master when issuing a STANDBY CLONE command."); - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); - ok = false; - } + /* + * To clone a master into a standby we need connection parameters + * repmgr.conf is useless because we don't have a server running in + * the standby; warn the user, but keep going. + */ + if (host == NULL) + { + fprintf(stderr, "\nYou need to use connection parameters to " + "the master when issuing a STANDBY CLONE command."); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); + ok = false; + } break; } diff --git a/repmgrd.c b/repmgrd.c index f31c452f..1922eb80 100644 --- a/repmgrd.c +++ b/repmgrd.c @@ -125,8 +125,8 @@ main(int argc, char **argv) verbose = true; break; default: - fprintf(stderr, _("Try \"%s --help\" for more information.\n"), - progname); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), + progname); exit(1); } } @@ -148,7 +148,7 @@ main(int argc, char **argv) if (config.node == -1) { fprintf(stderr, "Node information is missing. " - "Check the configuration file.\n"); + "Check the configuration file.\n"); exit(1); } @@ -160,7 +160,7 @@ main(int argc, char **argv) { PQfinish(myLocalConn); fprintf(stderr, _("%s needs standby to be PostgreSQL 9.0 or better\n"), - progname); + progname); exit(1); } @@ -179,8 +179,8 @@ main(int argc, char **argv) { /* I need the id of the primary as well as a connection to it */ primaryConn = getMasterConnection(myLocalConn, config.node, - config.cluster_name, &primaryId, - NULL); + config.cluster_name, &primaryId, + NULL); if (primaryConn == NULL) exit(1); @@ -247,13 +247,13 @@ MonitorExecute(void) if (PQstatus(primaryConn) != CONNECTION_OK) { fprintf(stderr, "\n%s: We couldn't reconnect to master, checking if ", - progname); + progname); for (connection_retries = 0; connection_retries < 6; - connection_retries++) + connection_retries++) { primaryConn = getMasterConnection(myLocalConn, config.node, - config.cluster_name, &primaryId, - NULL); + config.cluster_name, &primaryId, + NULL); if (PQstatus(primaryConn) == CONNECTION_OK) { @@ -294,9 +294,9 @@ MonitorExecute(void) /* Get local xlog info */ sqlquery_snprintf( - sqlquery, - "SELECT CURRENT_TIMESTAMP, pg_last_xlog_receive_location(), " - "pg_last_xlog_replay_location()"); + sqlquery, + "SELECT CURRENT_TIMESTAMP, pg_last_xlog_receive_location(), " + "pg_last_xlog_replay_location()"); res = PQexec(myLocalConn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -335,15 +335,15 @@ MonitorExecute(void) * Build the SQL to execute on primary */ sqlquery_snprintf(sqlquery, - "INSERT INTO repmgr_%s.repl_monitor " - "VALUES(%d, %d, '%s'::timestamp with time zone, " - " '%s', '%s', " - " %lld, %lld)", config.cluster_name, - primaryId, config.node, monitor_standby_timestamp, - last_wal_primary_location, - last_wal_standby_received, - (lsn_primary - lsn_standby_received), - (lsn_standby_received - lsn_standby_applied)); + "INSERT INTO repmgr_%s.repl_monitor " + "VALUES(%d, %d, '%s'::timestamp with time zone, " + " '%s', '%s', " + " %lld, %lld)", config.cluster_name, + primaryId, config.node, monitor_standby_timestamp, + last_wal_primary_location, + last_wal_standby_received, + (lsn_primary - lsn_standby_received), + (lsn_standby_received - lsn_standby_applied)); /* * Execute the query asynchronously, but don't check for a result. We @@ -351,7 +351,7 @@ MonitorExecute(void) */ if (PQsendQuery(primaryConn, sqlquery) == 0) fprintf(stderr, "Query could not be sent to primary. %s\n", - PQerrorMessage(primaryConn)); + PQerrorMessage(primaryConn)); } @@ -361,8 +361,8 @@ checkClusterConfiguration(void) PGresult *res; sqlquery_snprintf(sqlquery, "SELECT oid FROM pg_class " - " WHERE oid = 'repmgr_%s.repl_nodes'::regclass", - config.cluster_name); + " WHERE oid = 'repmgr_%s.repl_nodes'::regclass", + config.cluster_name); res = PQexec(myLocalConn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) { @@ -399,8 +399,8 @@ checkNodeConfiguration(char *conninfo) /* Check if we have my node information in repl_nodes */ sqlquery_snprintf(sqlquery, "SELECT * FROM repmgr_%s.repl_nodes " - " WHERE id = %d AND cluster = '%s' ", - config.cluster_name, config.node, config.cluster_name); + " WHERE id = %d AND cluster = '%s' ", + config.cluster_name, config.node, config.cluster_name); res = PQexec(myLocalConn, sqlquery); if (PQresultStatus(res) != PGRES_TUPLES_OK) @@ -422,13 +422,13 @@ checkNodeConfiguration(char *conninfo) /* Adding the node */ sqlquery_snprintf(sqlquery, "INSERT INTO repmgr_%s.repl_nodes " - "VALUES (%d, '%s', '%s')", - config.cluster_name, config.node, config.cluster_name, conninfo); + "VALUES (%d, '%s', '%s')", + config.cluster_name, config.node, config.cluster_name, conninfo); if (!PQexec(primaryConn, sqlquery)) { fprintf(stderr, "Cannot insert node details, %s\n", - PQerrorMessage(primaryConn)); + PQerrorMessage(primaryConn)); PQfinish(myLocalConn); PQfinish(primaryConn); exit(1);