From 9aca51250681d2e8d18ed1d73e7cd1283d1cf303 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 4 Apr 2014 18:42:13 -0400
Subject: [PATCH] Make sure -D is an absolute path when starting server on
 Windows.

This is needed because Windows services may get started with a different
current directory than where pg_ctl is executed.  We want relative -D
paths to be interpreted relative to pg_ctl's CWD, similarly to what
happens on other platforms.

In support of this, move the backend's make_absolute_path() function
into src/port/path.c (where it probably should have been long since)
and get rid of the rather inferior version in pg_regress.

Kumar Rajeev Rastogi, reviewed by MauMau
---
 src/backend/utils/init/miscinit.c |  71 -------------------
 src/bin/pg_ctl/pg_ctl.c           |  14 +++-
 src/include/miscadmin.h           |   1 -
 src/include/port.h                |   1 +
 src/port/path.c                   | 111 +++++++++++++++++++++++++++++-
 src/test/regress/pg_regress.c     |  27 --------
 6 files changed, 124 insertions(+), 101 deletions(-)

diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index c17bca83061..6115ce3f337 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -117,77 +117,6 @@ ChangeToDataDir(void)
 						DataDir)));
 }
 
-/*
- * If the given pathname isn't already absolute, make it so, interpreting
- * it relative to the current working directory.
- *
- * Also canonicalizes the path.  The result is always a malloc'd copy.
- *
- * Note: interpretation of relative-path arguments during postmaster startup
- * should happen before doing ChangeToDataDir(), else the user will probably
- * not like the results.
- */
-char *
-make_absolute_path(const char *path)
-{
-	char	   *new;
-
-	/* Returning null for null input is convenient for some callers */
-	if (path == NULL)
-		return NULL;
-
-	if (!is_absolute_path(path))
-	{
-		char	   *buf;
-		size_t		buflen;
-
-		buflen = MAXPGPATH;
-		for (;;)
-		{
-			buf = malloc(buflen);
-			if (!buf)
-				ereport(FATAL,
-						(errcode(ERRCODE_OUT_OF_MEMORY),
-						 errmsg("out of memory")));
-
-			if (getcwd(buf, buflen))
-				break;
-			else if (errno == ERANGE)
-			{
-				free(buf);
-				buflen *= 2;
-				continue;
-			}
-			else
-			{
-				free(buf);
-				elog(FATAL, "could not get current working directory: %m");
-			}
-		}
-
-		new = malloc(strlen(buf) + strlen(path) + 2);
-		if (!new)
-			ereport(FATAL,
-					(errcode(ERRCODE_OUT_OF_MEMORY),
-					 errmsg("out of memory")));
-		sprintf(new, "%s/%s", buf, path);
-		free(buf);
-	}
-	else
-	{
-		new = strdup(path);
-		if (!new)
-			ereport(FATAL,
-					(errcode(ERRCODE_OUT_OF_MEMORY),
-					 errmsg("out of memory")));
-	}
-
-	/* Make sure punctuation is canonical, too */
-	canonicalize_path(new);
-
-	return new;
-}
-
 
 /* ----------------------------------------------------------------
  *	User ID state
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 56d238f3948..1f921819c23 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1387,7 +1387,19 @@ pgwin32_CommandLine(bool registration)
 						  register_servicename);
 
 	if (pg_config)
-		appendPQExpBuffer(cmdLine, " -D \"%s\"", pg_config);
+	{
+		/* We need the -D path to be absolute */
+		char	   *dataDir;
+
+		if ((dataDir = make_absolute_path(pg_config)) == NULL)
+		{
+			/* make_absolute_path already reported the error */
+			exit(1);
+		}
+		make_native_path(dataDir);
+		appendPQExpBuffer(cmdLine, " -D \"%s\"", dataDir);
+		free(dataDir);
+	}
 
 	if (registration && do_wait)
 		appendPQExpBuffer(cmdLine, " -w");
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 947906a2805..0d61b82eb50 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -296,7 +296,6 @@ extern void SetCurrentRoleId(Oid roleid, bool is_superuser);
 
 extern void SetDataDir(const char *dir);
 extern void ChangeToDataDir(void);
-extern char *make_absolute_path(const char *path);
 
 /* in utils/misc/superuser.c */
 extern bool superuser(void);	/* current user is superuser */
diff --git a/src/include/port.h b/src/include/port.h
index aeb7754cb09..06986858b60 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -45,6 +45,7 @@ extern void make_native_path(char *path);
 extern bool path_contains_parent_reference(const char *path);
 extern bool path_is_relative_and_below_cwd(const char *path);
 extern bool path_is_prefix_of_path(const char *path1, const char *path2);
+extern char *make_absolute_path(const char *path);
 extern const char *get_progname(const char *argv0);
 extern void get_share_path(const char *my_exec_path, char *ret_path);
 extern void get_etc_path(const char *my_exec_path, char *ret_path);
diff --git a/src/port/path.c b/src/port/path.c
index 39d6e43404a..438b5296042 100644
--- a/src/port/path.c
+++ b/src/port/path.c
@@ -13,7 +13,11 @@
  *-------------------------------------------------------------------------
  */
 
-#include "c.h"
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
 
 #include <ctype.h>
 #include <sys/stat.h>
@@ -549,6 +553,111 @@ no_match:
 }
 
 
+/*
+ * make_absolute_path
+ *
+ * If the given pathname isn't already absolute, make it so, interpreting
+ * it relative to the current working directory.
+ *
+ * Also canonicalizes the path.  The result is always a malloc'd copy.
+ *
+ * In backend, failure cases result in ereport(ERROR); in frontend,
+ * we write a complaint on stderr and return NULL.
+ *
+ * Note: interpretation of relative-path arguments during postmaster startup
+ * should happen before doing ChangeToDataDir(), else the user will probably
+ * not like the results.
+ */
+char *
+make_absolute_path(const char *path)
+{
+	char	   *new;
+
+	/* Returning null for null input is convenient for some callers */
+	if (path == NULL)
+		return NULL;
+
+	if (!is_absolute_path(path))
+	{
+		char	   *buf;
+		size_t		buflen;
+
+		buflen = MAXPGPATH;
+		for (;;)
+		{
+			buf = malloc(buflen);
+			if (!buf)
+			{
+#ifndef FRONTEND
+				ereport(ERROR,
+						(errcode(ERRCODE_OUT_OF_MEMORY),
+						 errmsg("out of memory")));
+#else
+				fprintf(stderr, _("out of memory\n"));
+				return NULL;
+#endif
+			}
+
+			if (getcwd(buf, buflen))
+				break;
+			else if (errno == ERANGE)
+			{
+				free(buf);
+				buflen *= 2;
+				continue;
+			}
+			else
+			{
+				free(buf);
+#ifndef FRONTEND
+				elog(ERROR, "could not get current working directory: %m");
+#else
+				fprintf(stderr, _("could not get current working directory: %s\n"),
+						strerror(errno));
+				return NULL;
+#endif
+			}
+		}
+
+		new = malloc(strlen(buf) + strlen(path) + 2);
+		if (!new)
+		{
+			free(buf);
+#ifndef FRONTEND
+			ereport(ERROR,
+					(errcode(ERRCODE_OUT_OF_MEMORY),
+					 errmsg("out of memory")));
+#else
+			fprintf(stderr, _("out of memory\n"));
+			return NULL;
+#endif
+		}
+		sprintf(new, "%s/%s", buf, path);
+		free(buf);
+	}
+	else
+	{
+		new = strdup(path);
+		if (!new)
+		{
+#ifndef FRONTEND
+			ereport(ERROR,
+					(errcode(ERRCODE_OUT_OF_MEMORY),
+					 errmsg("out of memory")));
+#else
+			fprintf(stderr, _("out of memory\n"));
+			return NULL;
+#endif
+		}
+	}
+
+	/* Make sure punctuation is canonical, too */
+	canonicalize_path(new);
+
+	return new;
+}
+
+
 /*
  *	get_share_path
  */
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index abde5b477c6..07dd8037ac3 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -1855,33 +1855,6 @@ create_role(const char *rolename, const _stringlist * granted_dbs)
 	}
 }
 
-static char *
-make_absolute_path(const char *in)
-{
-	char	   *result;
-
-	if (is_absolute_path(in))
-		result = strdup(in);
-	else
-	{
-		static char cwdbuf[MAXPGPATH];
-
-		if (!cwdbuf[0])
-		{
-			if (!getcwd(cwdbuf, sizeof(cwdbuf)))
-			{
-				fprintf(stderr, _("could not get current working directory: %s\n"), strerror(errno));
-				exit(2);
-			}
-		}
-
-		result = psprintf("%s/%s", cwdbuf, in);
-	}
-
-	canonicalize_path(result);
-	return result;
-}
-
 static void
 help(void)
 {
-- 
GitLab