summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Deolasee2015-01-07 13:00:38 +0000
committerPavan Deolasee2015-04-15 05:49:14 +0000
commit1759a58ac03262b870904af45a826373f3594225 (patch)
tree3fc23a85fe10c97cbdac3da8ffd734731131bf21
parent873b408f762fae090c5721d3f4e3eedb4e26adc1 (diff)
Do not force remove data directories if they are not empty.
pgxc_ctl would try to cleanup specified directories (using rm -rf) even if they are not empty. It does so for GTM, datanodes, coordinators and all other components. This could lead to serious issues if user accidently specifies a wrong directory since it will wipe out everything under that directory. We now check if the directory is empty and then only proceed. Otherwise the initialization step will be skipped and existing data directory will be used to start the corresponding server. Also, we do this only for critical components such as datanodes, coordinators and GTM master. Other components such as datanode/coordinator/GTM slaves and GTM proxies can be recreated without any data loss.
-rw-r--r--contrib/pgxc_ctl/coord_cmd.c8
-rw-r--r--contrib/pgxc_ctl/datanode_cmd.c8
-rw-r--r--contrib/pgxc_ctl/gtm_cmd.c15
-rw-r--r--contrib/pgxc_ctl/utils.c61
-rw-r--r--contrib/pgxc_ctl/utils.h1
5 files changed, 91 insertions, 2 deletions
diff --git a/contrib/pgxc_ctl/coord_cmd.c b/contrib/pgxc_ctl/coord_cmd.c
index 891ab34703..1d4a1e5a23 100644
--- a/contrib/pgxc_ctl/coord_cmd.c
+++ b/contrib/pgxc_ctl/coord_cmd.c
@@ -77,6 +77,14 @@ cmd_t *prepare_initCoordinatorMaster(char *nodeName)
nodeName);
return(NULL);
}
+
+ if (pgxc_check_dir(aval(VAR_coordMasterDirs)[jj]) == 2)
+ {
+ elog(ERROR, "ERROR: target coordinator directory %s exists and is not empty. Skip initilialization.\n",
+ aval(VAR_coordMasterDirs)[jj]);
+ return NULL;
+ }
+
cmd = cmdInitdb = initCmd(aval(VAR_coordMasterServers)[jj]);
snprintf(newCommand(cmdInitdb), MAXLINE,
"rm -rf %s;"
diff --git a/contrib/pgxc_ctl/datanode_cmd.c b/contrib/pgxc_ctl/datanode_cmd.c
index c5a9f61f5b..b86ca4ded6 100644
--- a/contrib/pgxc_ctl/datanode_cmd.c
+++ b/contrib/pgxc_ctl/datanode_cmd.c
@@ -67,6 +67,14 @@ cmd_t *prepare_initDatanodeMaster(char *nodeName)
if ((idx = datanodeIdx(nodeName)) < 0)
return(NULL);
+
+ if (pgxc_check_dir(aval(VAR_datanodeMasterDirs)[idx]) == 2)
+ {
+ elog(ERROR, "ERROR: target datanode directory %s exists and is not empty. Skip initilialization.\n",
+ aval(VAR_datanodeMasterDirs)[idx]);
+ return NULL;
+ }
+
/* Build each datanode's initialize command */
cmd = cmdInitdb = initCmd(aval(VAR_datanodeMasterServers)[idx]);
snprintf(newCommand(cmdInitdb), MAXLINE,
diff --git a/contrib/pgxc_ctl/gtm_cmd.c b/contrib/pgxc_ctl/gtm_cmd.c
index c7be7ab09c..c7879bb3a2 100644
--- a/contrib/pgxc_ctl/gtm_cmd.c
+++ b/contrib/pgxc_ctl/gtm_cmd.c
@@ -53,6 +53,16 @@ cmd_t *prepare_initGtmMaster(void)
char date[MAXTOKEN+1];
FILE *f;
char **fileList = NULL;
+ int result;
+
+ result = pgxc_check_dir(sval(VAR_gtmMasterDir));
+
+ if (result == 2)
+ {
+ elog(ERROR, "ERROR: target GTM directory %s exists and is not empty. Skip initilialization.\n",
+ sval(VAR_gtmMasterDir));
+ return NULL;
+ }
/* Kill current gtm, bild work directory and run initgtm */
cmdInitGtmMaster = initCmd(sval(VAR_gtmMasterServer));
@@ -106,13 +116,16 @@ int init_gtm_master(void)
{
int rc;
cmdList_t *cmdList;
+ cmd_t *cmd;
elog(INFO, "Initialize GTM master\n");
cmdList = initCmdList();
/* Kill current gtm, build work directory and run initgtm */
- addCmd(cmdList, prepare_initGtmMaster());
+ if ((cmd = prepare_initGtmMaster()))
+ addCmd(cmdList, cmd);
+
rc = doCmdList(cmdList);
cleanCmdList(cmdList);
elog(INFO, "Done.\n");
diff --git a/contrib/pgxc_ctl/utils.c b/contrib/pgxc_ctl/utils.c
index 279ecca5c6..dd79fa10dc 100644
--- a/contrib/pgxc_ctl/utils.c
+++ b/contrib/pgxc_ctl/utils.c
@@ -14,6 +14,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
+#include <dirent.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
@@ -28,6 +29,8 @@
#include "config.h"
#include "variables.h"
#include "varnames.h"
+#include "c.h"
+
static int Malloc_ed = 0;
static int Strdup_ed = 0;
@@ -368,4 +371,60 @@ char *getIpAddress(char *hostName)
trimNl(ipAddr);
return ipAddr;
}
-
+
+
+/*
+ * Test to see if a directory exists and is empty or not.
+ *
+ * Returns:
+ * 0 if nonexistent
+ * 1 if exists and empty
+ * 2 if exists and not empty
+ * -1 if trouble accessing directory (errno reflects the error)
+ */
+int
+pgxc_check_dir(const char *dir)
+{
+ int result = 1;
+ DIR *chkdir;
+ struct dirent *file;
+
+ errno = 0;
+
+ chkdir = opendir(dir);
+
+ if (chkdir == NULL)
+ 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;
+ }
+ }
+
+#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;
+#endif
+
+ closedir(chkdir);
+
+ if (errno != 0)
+ result = -1; /* some kind of I/O error? */
+
+ return result;
+}
diff --git a/contrib/pgxc_ctl/utils.h b/contrib/pgxc_ctl/utils.h
index d2a7eb4500..6d0fb9d691 100644
--- a/contrib/pgxc_ctl/utils.h
+++ b/contrib/pgxc_ctl/utils.h
@@ -33,6 +33,7 @@ extern int pingNode(char *host, char *port);
extern void trimNl(char *s);
extern char *getChPidList(char *host, pid_t ppid);
extern char *getIpAddress(char *hostName);
+extern int pgxc_check_dir(const char *dir);
#define get_postmaster_pid(host, dir) get_prog_pid(host, "postmaster", dir)
#define get_gtm_pid(host, dir) get_prog_pid(host, "gtm", dir)