diff --git a/configure b/configure
index 7e0a563444df053f902c68961593c3ff4a9f8a56..b53dc7723083b9db02aff424b558dc0d5e592a3f 100755
--- a/configure
+++ b/configure
@@ -11295,7 +11295,8 @@ test $ac_cv_func_memcmp_working = no && LIBOBJS="$LIBOBJS memcmp.$ac_objext"
 
 
 
-for ac_func in cbrt dlopen fcvt fdatasync getpeereid memmove poll pstat setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs
+
+for ac_func in cbrt dlopen fcvt fdatasync getpeereid memmove poll pstat readlink setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
 echo "$as_me:$LINENO: checking for $ac_func" >&5
diff --git a/configure.in b/configure.in
index 14af5ae0279a2d878c6882b5cb7a3494571ae152..6eb4e120b027e2f605df6d65f933f0b755d7437b 100644
--- a/configure.in
+++ b/configure.in
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-dnl $PostgreSQL: pgsql/configure.in,v 1.384 2004/11/02 05:44:45 momjian Exp $
+dnl $PostgreSQL: pgsql/configure.in,v 1.385 2004/11/06 23:06:15 tgl Exp $
 dnl
 dnl Developers, please strive to achieve this order:
 dnl
@@ -826,7 +826,7 @@ PGAC_FUNC_GETTIMEOFDAY_1ARG
 # SunOS doesn't handle negative byte comparisons properly with +/- return
 AC_FUNC_MEMCMP
 
-AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getpeereid memmove poll pstat setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs])
+AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getpeereid memmove poll pstat readlink setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs])
 
 AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
 
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 600f4229f0a1c1dd239586db9217a9d10ae41265..279b6b539c8879c84d2c94755d53016b4541ae60 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -345,6 +345,9 @@
 /* Define to 1 if you have the <readline/readline.h> header file. */
 #undef HAVE_READLINE_READLINE_H
 
+/* Define to 1 if you have the `readlink' function. */
+#undef HAVE_READLINK
+
 /* Define to 1 if you have the `replace_history_entry' function. */
 #undef HAVE_REPLACE_HISTORY_ENTRY
 
diff --git a/src/port/exec.c b/src/port/exec.c
index 839bc73f00514859f02f13dcc9725a0e839fc64f..28b25c4b7f99ac99ec5a3b1066f601ed6c573bce 100644
--- a/src/port/exec.c
+++ b/src/port/exec.c
@@ -1,13 +1,15 @@
 /*-------------------------------------------------------------------------
  *
  * exec.c
+ *		Functions for finding and validating executable files
+ *
  *
  * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/port/exec.c,v 1.31 2004/11/06 01:16:22 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/port/exec.c,v 1.32 2004/11/06 23:06:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,6 +49,14 @@
 #define log_error(str, param)	(fprintf(stderr, str, param), fputc('\n', stderr))
 #endif
 
+#ifdef WIN32_CLIENT_ONLY
+#define getcwd(cwd,len)  GetCurrentDirectory(len, cwd)
+#endif
+
+static int	validate_exec(const char *path);
+static int	resolve_symlinks(char *path);
+static char *pipe_read_line(char *cmd, char *line, int maxsize);
+
 
 /*
  * validate_exec -- validate "path" as an executable file
@@ -154,13 +164,20 @@ validate_exec(const char *path)
 #endif
 }
 
+
 /*
  * find_my_exec -- find an absolute path to a valid executable
  *
+ *	argv0 is the name passed on the command line
+ *	retpath is the output area (must be of size MAXPGPATH)
+ *	Returns 0 if OK, -1 if error.
+ *
  * The reason we have to work so hard to find an absolute path is that
  * on some platforms we can't do dynamic loading unless we know the
  * executable's location.  Also, we need a full path not a relative
- * path because we will later change working directory.
+ * path because we will later change working directory.  Finally, we want
+ * a true path not a symlink location, so that we can locate other files
+ * that are part of our installation relative to the executable.
  *
  * This function is not thread-safe because it calls validate_exec(),
  * which calls getgrgid().	This function should be used only in
@@ -173,13 +190,12 @@ find_my_exec(const char *argv0, char *retpath)
 				test_path[MAXPGPATH];
 	char	   *path;
 
-#ifndef WIN32_CLIENT_ONLY
 	if (!getcwd(cwd, MAXPGPATH))
-		strcpy(cwd, ".");		/* cheesy, but better than nothing */
-#else
-	if (!GetCurrentDirectory(MAXPGPATH, cwd))
-		strcpy(cwd, ".");		/* cheesy, but better than nothing */
-#endif
+	{
+		log_error(_("could not identify current directory: %s"),
+				  strerror(errno));
+		return -1;
+	}
 
 	/*
 	 * If argv0 contains a separator, then PATH wasn't used.
@@ -193,7 +209,7 @@ find_my_exec(const char *argv0, char *retpath)
 		canonicalize_path(retpath);
 
 		if (validate_exec(retpath) == 0)
-			return 0;
+			return resolve_symlinks(retpath);
 
 		log_error("invalid binary \"%s\"", retpath);
 		return -1;
@@ -203,7 +219,7 @@ find_my_exec(const char *argv0, char *retpath)
 	/* Win32 checks the current directory first for names without slashes */
 	join_path_components(retpath, cwd, argv0);
 	if (validate_exec(retpath) == 0)
-		return 0;
+		return resolve_symlinks(retpath);
 #endif
 
 	/*
@@ -240,7 +256,7 @@ find_my_exec(const char *argv0, char *retpath)
 			switch (validate_exec(retpath))
 			{
 				case 0:			/* found ok */
-					return 0;
+					return resolve_symlinks(retpath);
 				case -1:		/* wasn't even a candidate, keep looking */
 					break;
 				case -2:		/* found but disqualified */
@@ -254,6 +270,141 @@ find_my_exec(const char *argv0, char *retpath)
 	return -1;
 }
 
+
+/*
+ * resolve_symlinks - resolve symlinks to the underlying file
+ *
+ * If path does not point to a symlink, leave it alone.  If it does,
+ * replace it by the absolute path to the referenced file.
+ *
+ * Returns 0 if OK, -1 if error.
+ *
+ * Note: we are not particularly tense about producing nice error messages
+ * because we are not really expecting error here; we just determined that
+ * the symlink does point to a valid executable.
+ */
+static int
+resolve_symlinks(char *path)
+{
+#ifdef HAVE_READLINK
+	struct stat buf;
+	char		orig_wd[MAXPGPATH],
+				link_buf[MAXPGPATH];
+	char	   *fname;
+
+	/* Quick out if it's not a symlink */
+	if (lstat(path, &buf) < 0 ||
+		(buf.st_mode & S_IFMT) != S_IFLNK)
+		return 0;
+
+	/*
+	 * To resolve a symlink properly, we have to chdir into its directory
+	 * and then chdir to where the symlink points; otherwise we may fail to
+	 * resolve relative links correctly (consider cases involving mount
+	 * points, for example).  After following the final symlink, we use
+	 * getcwd() to figure out where the heck we're at.
+	 */
+	if (!getcwd(orig_wd, MAXPGPATH))
+	{
+		log_error(_("could not identify current directory: %s"),
+				  strerror(errno));
+		return -1;
+	}
+
+	for (;;)
+	{
+		char   *lsep;
+		int		rllen;
+
+		lsep = last_dir_separator(path);
+		if (lsep)
+		{
+			*lsep = '\0';
+			if (chdir(path) == -1)
+			{
+				log_error(_("could not change directory to \"%s\""), path);
+				return -1;
+			}
+			fname = lsep + 1;
+		}
+		else
+			fname = path;
+
+		if (lstat(fname, &buf) < 0 ||
+			(buf.st_mode & S_IFMT) != S_IFLNK)
+			break;
+
+		rllen = readlink(fname, link_buf, sizeof(link_buf));
+		if (rllen < 0 || rllen >= sizeof(link_buf))
+		{
+			log_error(_("could not read symbolic link \"%s\""), fname);
+			return -1;
+		}
+		link_buf[rllen] = '\0';
+		strcpy(path, link_buf);
+	}
+
+	/* must copy final component out of 'path' temporarily */
+	strcpy(link_buf, fname);
+
+	if (!getcwd(path, MAXPGPATH))
+	{
+		log_error(_("could not identify current directory: %s"),
+				  strerror(errno));
+		return -1;
+	}
+	join_path_components(path, path, link_buf);
+	canonicalize_path(path);
+
+	if (chdir(orig_wd) == -1)
+	{
+		log_error(_("could not change directory to \"%s\""), orig_wd);
+		return -1;
+	}
+
+#endif /* HAVE_READLINK */
+
+	return 0;
+}
+
+
+/*
+ * Find another program in our binary's directory,
+ * then make sure it is the proper version.
+ */
+int
+find_other_exec(const char *argv0, const char *target,
+				const char *versionstr, char *retpath)
+{
+	char		cmd[MAXPGPATH];
+	char		line[100];
+
+	if (find_my_exec(argv0, retpath) < 0)
+		return -1;
+
+	/* Trim off program name and keep just directory */
+	*last_dir_separator(retpath) = '\0';
+	canonicalize_path(retpath);
+
+	/* Now append the other program's name */
+	snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath),
+			 "/%s%s", target, EXE);
+
+	if (validate_exec(retpath) != 0)
+		return -1;
+
+	snprintf(cmd, sizeof(cmd), "\"%s\" -V 2>%s", retpath, DEVNULL);
+
+	if (!pipe_read_line(cmd, line, sizeof(line)))
+		return -1;
+
+	if (strcmp(line, versionstr) != 0)
+		return -2;
+
+	return 0;
+}
+
+
 /*
  * The runtime library's popen() on win32 does not work when being
  * called from a service when running on windows <= 2000, because
@@ -262,7 +413,6 @@ find_my_exec(const char *argv0, char *retpath)
  * Executing a command in a pipe and reading the first line from it
  * is all we need.
  */
-
 static char *
 pipe_read_line(char *cmd, char *line, int maxsize)
 {
@@ -286,8 +436,9 @@ pipe_read_line(char *cmd, char *line, int maxsize)
 		return NULL;
 
 	return line;
-#else
-	/* Win32 */
+
+#else /* WIN32 */
+
 	SECURITY_ATTRIBUTES sattr;
 	HANDLE		childstdoutrd,
 				childstdoutwr,
@@ -392,44 +543,7 @@ pipe_read_line(char *cmd, char *line, int maxsize)
 	CloseHandle(childstdoutrddup);
 
 	return retval;
-#endif
-}
-
-
-/*
- * Find another program in our binary's directory,
- * then make sure it is the proper version.
- */
-int
-find_other_exec(const char *argv0, const char *target,
-				const char *versionstr, char *retpath)
-{
-	char		cmd[MAXPGPATH];
-	char		line[100];
-
-	if (find_my_exec(argv0, retpath) < 0)
-		return -1;
-
-	/* Trim off program name and keep just directory */
-	*last_dir_separator(retpath) = '\0';
-	canonicalize_path(retpath);
-
-	/* Now append the other program's name */
-	snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath),
-			 "/%s%s", target, EXE);
-
-	if (validate_exec(retpath))
-		return -1;
-
-	snprintf(cmd, sizeof(cmd), "\"%s\" -V 2>%s", retpath, DEVNULL);
-
-	if (!pipe_read_line(cmd, line, sizeof(line)))
-		return -1;
-
-	if (strcmp(line, versionstr) != 0)
-		return -2;
-
-	return 0;
+#endif /* WIN32 */
 }
 
 
@@ -454,20 +568,14 @@ pclose_check(FILE *stream)
 		perror("pclose failed");
 	}
 	else if (WIFEXITED(exitstatus))
-	{
 		log_error(_("child process exited with exit code %d"),
 				  WEXITSTATUS(exitstatus));
-	}
 	else if (WIFSIGNALED(exitstatus))
-	{
 		log_error(_("child process was terminated by signal %d"),
 				  WTERMSIG(exitstatus));
-	}
 	else
-	{
 		log_error(_("child process exited with unrecognized status %d"),
 				  exitstatus);
-	}
 
 	return -1;
 }