6cb03e
Back-port of upstream 9.3 patch to support multiple sockets
6cb03e
(upstream git commits c9b0cbe98bd783e24a8c4d8d8ac472a494b81292 and
6cb03e
d2286a98ef3fb88bafb57381b4c20b8b878827f1, plus updates of derived
6cb03e
documentation files).
6cb03e
6cb03e
Note the patch also touches html-stamp and man-stamp in doc/src/sgml/;
6cb03e
this is to keep the makefiles from trying to rebuild the derived doc
6cb03e
files.  We don't want that to happen because the BuildRequires for the
6cb03e
package don't include the necessary documentation tools.  Those diff
6cb03e
hunks *must be at the end* so that those files are newer than the
6cb03e
master doc files.
6cb03e
6cb03e
diff --git a/contrib/pg_upgrade/server.c b/contrib/pg_upgrade/server.c
6cb03e
index 0940e00..c5ecb84 100644
6cb03e
--- a/contrib/pg_upgrade/server.c
6cb03e
+++ b/contrib/pg_upgrade/server.c
6cb03e
@@ -197,7 +197,8 @@ start_postmaster(ClusterInfo *cluster)
6cb03e
 		snprintf(socket_string + strlen(socket_string),
6cb03e
 				 sizeof(socket_string) - strlen(socket_string),
6cb03e
 				 " -c %s='%s'",
6cb03e
-				 (GET_MAJOR_VERSION(cluster->major_version) < 903) ?
6cb03e
+	/* assume 9.1 build will not have unix_socket_directories patch */
6cb03e
+				 (GET_MAJOR_VERSION(cluster->major_version) < 902) ?
6cb03e
 				 "unix_socket_directory" : "unix_socket_directories",
6cb03e
 				 cluster->sockdir);
6cb03e
 #endif
6cb03e
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
6cb03e
index b9664cb..94e166d 100644
6cb03e
--- a/doc/src/sgml/client-auth.sgml
6cb03e
+++ b/doc/src/sgml/client-auth.sgml
6cb03e
@@ -838,7 +838,7 @@ omicron         bryanh                  guest1
6cb03e
     <varname>unix_socket_permissions</varname> (and possibly
6cb03e
     <varname>unix_socket_group</varname>) configuration parameters as
6cb03e
     described in <xref linkend="runtime-config-connection">.  Or you
6cb03e
-    could set the <varname>unix_socket_directory</varname>
6cb03e
+    could set the <varname>unix_socket_directories</varname>
6cb03e
     configuration parameter to place the socket file in a suitably
6cb03e
     restricted directory.
6cb03e
    </para>
6cb03e
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
6cb03e
index 51d7da9..cb5c5d2 100644
6cb03e
--- a/doc/src/sgml/config.sgml
6cb03e
+++ b/doc/src/sgml/config.sgml
6cb03e
@@ -453,17 +453,24 @@ SET ENABLE_SEQSCAN TO OFF;
6cb03e
       </listitem>
6cb03e
      </varlistentry>
6cb03e
 
6cb03e
-     <varlistentry id="guc-unix-socket-directory" xreflabel="unix_socket_directory">
6cb03e
-      <term><varname>unix_socket_directory</varname> (<type>string</type>)</term>
6cb03e
+     <varlistentry id="guc-unix-socket-directories" xreflabel="unix_socket_directories">
6cb03e
+      <term><varname>unix_socket_directories</varname> (<type>string</type>)</term>
6cb03e
       <indexterm>
6cb03e
-       <primary><varname>unix_socket_directory configuration parameter</primary>
6cb03e
+       <primary><varname>unix_socket_directories configuration parameter</primary>
6cb03e
       </indexterm>
6cb03e
       <listitem>
6cb03e
        <para>
6cb03e
-        Specifies the directory of the Unix-domain socket on which the
6cb03e
-        server is to listen for
6cb03e
-        connections from client applications.  The default is normally
6cb03e
-        <filename>/tmp</filename>, but can be changed at build time.
6cb03e
+        Specifies the directory of the Unix-domain socket(s) on which the
6cb03e
+        server is to listen for connections from client applications.
6cb03e
+        Multiple sockets can be created by listing multiple directories
6cb03e
+        separated by commas.  Whitespace between entries is
6cb03e
+        ignored; surround a directory name with double quotes if you need
6cb03e
+        to include whitespace or commas in the name.
6cb03e
+        An empty value
6cb03e
+        specifies not listening on any Unix-domain sockets, in which case
6cb03e
+        only TCP/IP sockets can be used to connect to the server.
6cb03e
+        The default value is normally
6cb03e
+        <filename>/tmp</filename>, but that can be changed at build time.
6cb03e
         This parameter can only be set at server start.
6cb03e
        </para>
6cb03e
 
6cb03e
@@ -472,8 +479,8 @@ SET ENABLE_SEQSCAN TO OFF;
6cb03e
         <literal>.s.PGSQL.<replaceable>nnnn</literal> where
6cb03e
         <replaceable>nnnn is the server's port number, an ordinary file
6cb03e
         named <literal>.s.PGSQL.<replaceable>nnnn.lock</literal> will be
6cb03e
-        created in the <varname>unix_socket_directory directory.  Neither
6cb03e
-        file should ever be removed manually.
6cb03e
+        created in each of the <varname>unix_socket_directories directories.
6cb03e
+        Neither file should ever be removed manually.
6cb03e
        </para>
6cb03e
 
6cb03e
        <para>
6cb03e
@@ -490,8 +497,8 @@ SET ENABLE_SEQSCAN TO OFF;
6cb03e
       </indexterm>
6cb03e
       <listitem>
6cb03e
        <para>
6cb03e
-        Sets the owning group of the Unix-domain socket.  (The owning
6cb03e
-        user of the socket is always the user that starts the
6cb03e
+        Sets the owning group of the Unix-domain socket(s).  (The owning
6cb03e
+        user of the sockets is always the user that starts the
6cb03e
         server.)  In combination with the parameter
6cb03e
         <varname>unix_socket_permissions</varname> this can be used as
6cb03e
         an additional access control mechanism for Unix-domain connections.
6cb03e
@@ -514,7 +521,7 @@ SET ENABLE_SEQSCAN TO OFF;
6cb03e
       </indexterm>
6cb03e
       <listitem>
6cb03e
        <para>
6cb03e
-        Sets the access permissions of the Unix-domain socket.  Unix-domain
6cb03e
+        Sets the access permissions of the Unix-domain socket(s).  Unix-domain
6cb03e
         sockets use the usual Unix file system permission set.
6cb03e
         The parameter value is expected to be a numeric mode
6cb03e
         specified in the format accepted by the
6cb03e
@@ -6624,7 +6631,7 @@ LOG:  CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1)
6cb03e
        </row>
6cb03e
        <row>
6cb03e
         <entry><option>-k <replaceable>x</replaceable></option></entry>
6cb03e
-        <entry><literal>unix_socket_directory = <replaceable>x</replaceable></entry>
6cb03e
+        <entry><literal>unix_socket_directories = <replaceable>x</replaceable></entry>
6cb03e
        </row>
6cb03e
        <row>
6cb03e
         <entry><option>-l</option></entry>
6cb03e
diff --git a/doc/src/sgml/html/app-postgres.html b/doc/src/sgml/html/app-postgres.html
6cb03e
index b1f4e31..b6359a8 100644
6cb03e
--- a/doc/src/sgml/html/app-postgres.html
6cb03e
+++ b/doc/src/sgml/html/app-postgres.html
6cb03e
@@ -574,11 +574,19 @@ CLASS="REPLACEABLE"
6cb03e
 CLASS="COMMAND"
6cb03e
 >postgres
6cb03e
 > is to listen for
6cb03e
-        connections from client applications.  The default is normally
6cb03e
+        connections from client applications.  The value can also be a
6cb03e
+        comma-separated list of directories.  An empty value
6cb03e
+        specifies not listening on any Unix-domain sockets, in which case
6cb03e
+        only TCP/IP sockets can be used to connect to the server.
6cb03e
+        The default value is normally
6cb03e
         
6cb03e
 CLASS="FILENAME"
6cb03e
 >/tmp
6cb03e
->, but can be changed at build time.
6cb03e
+>, but that can be changed at build time.
6cb03e
+        Specifying this option is equivalent to setting the 
6cb03e
+HREF="runtime-config-connection.html#GUC-UNIX-SOCKET-DIRECTORIES"
6cb03e
+>unix_socket_directories
6cb03e
+> configuration parameter.
6cb03e
        
6cb03e
 >
6cb03e
 >
6cb03e
diff --git a/doc/src/sgml/html/auth-methods.html b/doc/src/sgml/html/auth-methods.html
6cb03e
index ab544a9..e1225d1 100644
6cb03e
--- a/doc/src/sgml/html/auth-methods.html
6cb03e
+++ b/doc/src/sgml/html/auth-methods.html
6cb03e
@@ -161,7 +161,7 @@ HREF="runtime-config-connection.html"
6cb03e
 >.  Or you
6cb03e
     could set the 
6cb03e
 CLASS="VARNAME"
6cb03e
->unix_socket_directory
6cb03e
+>unix_socket_directories
6cb03e
 >
6cb03e
     configuration parameter to place the socket file in a suitably
6cb03e
     restricted directory.
6cb03e
diff --git a/doc/src/sgml/html/bookindex.html b/doc/src/sgml/html/bookindex.html
6cb03e
index 5e25f95..1562ffe 100644
6cb03e
--- a/doc/src/sgml/html/bookindex.html
6cb03e
+++ b/doc/src/sgml/html/bookindex.html
6cb03e
@@ -17250,7 +17250,7 @@ HREF="xfunc-c.html#DFUNC"
6cb03e
 >
6cb03e
 >
6cb03e
 >
6cb03e
->unix_socket_directory configuration parameter,
6cb03e
+>unix_socket_directories configuration parameter,
6cb03e
     
6cb03e
 HREF="runtime-config-connection.html#RUNTIME-CONFIG-CONNECTION-SETTINGS"
6cb03e
 >Connection Settings
6cb03e
diff --git a/doc/src/sgml/html/preventing-server-spoofing.html b/doc/src/sgml/html/preventing-server-spoofing.html
6cb03e
index 77d11ab..6abc511 100644
6cb03e
--- a/doc/src/sgml/html/preventing-server-spoofing.html
6cb03e
+++ b/doc/src/sgml/html/preventing-server-spoofing.html
6cb03e
@@ -115,8 +115,8 @@ CLASS="LITERAL"
6cb03e
 >local
6cb03e
 >
6cb03e
    connections is to use a Unix domain socket directory (
6cb03e
-HREF="runtime-config-connection.html#GUC-UNIX-SOCKET-DIRECTORY"
6cb03e
->unix_socket_directory
6cb03e
+HREF="runtime-config-connection.html#GUC-UNIX-SOCKET-DIRECTORIES"
6cb03e
+>unix_socket_directories
6cb03e
 >) that has write permission only
6cb03e
    for a trusted local user.  This prevents a malicious user from creating
6cb03e
    their own socket file in that directory.  If you are concerned that
6cb03e
diff --git a/doc/src/sgml/html/runtime-config-connection.html b/doc/src/sgml/html/runtime-config-connection.html
6cb03e
index 74f096e..0ba6987 100644
6cb03e
--- a/doc/src/sgml/html/runtime-config-connection.html
6cb03e
+++ b/doc/src/sgml/html/runtime-config-connection.html
6cb03e
@@ -274,24 +274,31 @@ CLASS="VARNAME"
6cb03e
 >
6cb03e
 >
6cb03e
 >
6cb03e
-NAME="GUC-UNIX-SOCKET-DIRECTORY"
6cb03e
+NAME="GUC-UNIX-SOCKET-DIRECTORIES"
6cb03e
 >
6cb03e
 >
6cb03e
 CLASS="VARNAME"
6cb03e
->unix_socket_directory
6cb03e
+>unix_socket_directories
6cb03e
 > (
6cb03e
 CLASS="TYPE"
6cb03e
 >string
6cb03e
 >)
6cb03e
 >
6cb03e
 >
6cb03e
->        Specifies the directory of the Unix-domain socket on which the
6cb03e
-        server is to listen for
6cb03e
-        connections from client applications.  The default is normally
6cb03e
+>        Specifies the directory of the Unix-domain socket(s) on which the
6cb03e
+        server is to listen for connections from client applications.
6cb03e
+        Multiple sockets can be created by listing multiple directories
6cb03e
+        separated by commas.  Whitespace between entries is
6cb03e
+        ignored; surround a directory name with double quotes if you need
6cb03e
+        to include whitespace or commas in the name.
6cb03e
+        An empty value
6cb03e
+        specifies not listening on any Unix-domain sockets, in which case
6cb03e
+        only TCP/IP sockets can be used to connect to the server.
6cb03e
+        The default value is normally
6cb03e
         
6cb03e
 CLASS="FILENAME"
6cb03e
 >/tmp
6cb03e
->, but can be changed at build time.
6cb03e
+>, but that can be changed at build time.
6cb03e
         This parameter can only be set at server start.
6cb03e
        
6cb03e
 >
6cb03e
@@ -320,11 +327,11 @@ CLASS="REPLACEABLE"
6cb03e
 >
6cb03e
 >.lock
6cb03e
 > will be
6cb03e
-        created in the 
6cb03e
+        created in each of the 
6cb03e
 CLASS="VARNAME"
6cb03e
->unix_socket_directory
6cb03e
-> directory.  Neither
6cb03e
-        file should ever be removed manually.
6cb03e
+>unix_socket_directories
6cb03e
+> directories.
6cb03e
+        Neither file should ever be removed manually.
6cb03e
        
6cb03e
 >
6cb03e
 >        This parameter is irrelevant on Windows, which does not have
6cb03e
@@ -344,8 +351,8 @@ CLASS="TYPE"
6cb03e
 >)
6cb03e
 >
6cb03e
 >
6cb03e
->        Sets the owning group of the Unix-domain socket.  (The owning
6cb03e
-        user of the socket is always the user that starts the
6cb03e
+>        Sets the owning group of the Unix-domain socket(s).  (The owning
6cb03e
+        user of the sockets is always the user that starts the
6cb03e
         server.)  In combination with the parameter
6cb03e
         
6cb03e
 CLASS="VARNAME"
6cb03e
@@ -374,7 +381,7 @@ CLASS="TYPE"
6cb03e
 >)
6cb03e
 >
6cb03e
 >
6cb03e
->        Sets the access permissions of the Unix-domain socket.  Unix-domain
6cb03e
+>        Sets the access permissions of the Unix-domain socket(s).  Unix-domain
6cb03e
         sockets use the usual Unix file system permission set.
6cb03e
         The parameter value is expected to be a numeric mode
6cb03e
         specified in the format accepted by the
6cb03e
diff --git a/doc/src/sgml/html/runtime-config-short.html b/doc/src/sgml/html/runtime-config-short.html
6cb03e
index 8c39c2f..f0d7080 100644
6cb03e
--- a/doc/src/sgml/html/runtime-config-short.html
6cb03e
+++ b/doc/src/sgml/html/runtime-config-short.html
6cb03e
@@ -330,7 +330,7 @@ CLASS="REPLACEABLE"
6cb03e
 >
6cb03e
 >
6cb03e
 CLASS="LITERAL"
6cb03e
->unix_socket_directory = 
6cb03e
+>unix_socket_directories = 
6cb03e
 CLASS="REPLACEABLE"
6cb03e
 >
6cb03e
 >x
6cb03e
diff --git a/doc/src/sgml/man1/postgres.1 b/doc/src/sgml/man1/postgres.1
6cb03e
index 6ec18ee..3378dde 100644
6cb03e
--- a/doc/src/sgml/man1/postgres.1
6cb03e
+++ b/doc/src/sgml/man1/postgres.1
6cb03e
@@ -195,8 +195,10 @@ directly\&.
6cb03e
 .RS 4
6cb03e
 Specifies the directory of the Unix\-domain socket on which
6cb03e
 \fBpostgres\fR
6cb03e
-is to listen for connections from client applications\&. The default is normally
6cb03e
-/tmp, but can be changed at build time\&.
6cb03e
+is to listen for connections from client applications\&. The value can also be a comma\-separated list of directories\&. An empty value specifies not listening on any Unix\-domain sockets, in which case only TCP/IP sockets can be used to connect to the server\&. The default value is normally
6cb03e
+/tmp, but that can be changed at build time\&. Specifying this option is equivalent to setting the
6cb03e
+unix_socket_directories
6cb03e
+configuration parameter\&.
6cb03e
 .RE
6cb03e
 .PP
6cb03e
 \fB\-l\fR
6cb03e
diff --git a/doc/src/sgml/ref/postgres-ref.sgml b/doc/src/sgml/ref/postgres-ref.sgml
6cb03e
index 4e5cd02..a1f36e1 100644
6cb03e
--- a/doc/src/sgml/ref/postgres-ref.sgml
6cb03e
+++ b/doc/src/sgml/ref/postgres-ref.sgml
6cb03e
@@ -254,8 +254,14 @@ PostgreSQL documentation
6cb03e
        <para>
6cb03e
         Specifies the directory of the Unix-domain socket on which
6cb03e
         <command>postgres</command> is to listen for
6cb03e
-        connections from client applications.  The default is normally
6cb03e
-        <filename>/tmp</filename>, but can be changed at build time.
6cb03e
+        connections from client applications.  The value can also be a
6cb03e
+        comma-separated list of directories.  An empty value
6cb03e
+        specifies not listening on any Unix-domain sockets, in which case
6cb03e
+        only TCP/IP sockets can be used to connect to the server.
6cb03e
+        The default value is normally
6cb03e
+        <filename>/tmp</filename>, but that can be changed at build time.
6cb03e
+        Specifying this option is equivalent to setting the 
6cb03e
+        linkend="guc-unix-socket-directories"> configuration parameter.
6cb03e
        </para>
6cb03e
       </listitem>
6cb03e
      </varlistentry>
6cb03e
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
6cb03e
index cfd3532..e6c9eaa 100644
6cb03e
--- a/doc/src/sgml/runtime.sgml
6cb03e
+++ b/doc/src/sgml/runtime.sgml
6cb03e
@@ -1800,7 +1800,7 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
6cb03e
   <para>
6cb03e
    The simplest way to prevent spoofing for <literal>local
6cb03e
    connections is to use a Unix domain socket directory (
6cb03e
-   linkend="guc-unix-socket-directory">) that has write permission only
6cb03e
+   linkend="guc-unix-socket-directories">) that has write permission only
6cb03e
    for a trusted local user.  This prevents a malicious user from creating
6cb03e
    their own socket file in that directory.  If you are concerned that
6cb03e
    some applications might still reference <filename>/tmp for the
6cb03e
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
6cb03e
index aeeffd7..b7e0d09 100644
6cb03e
--- a/src/backend/libpq/pqcomm.c
6cb03e
+++ b/src/backend/libpq/pqcomm.c
6cb03e
@@ -42,7 +42,7 @@
6cb03e
  *		StreamServerPort	- Open postmaster's server port
6cb03e
  *		StreamConnection	- Create new connection with client
6cb03e
  *		StreamClose			- Close a client/backend connection
6cb03e
- *		TouchSocketFile		- Protect socket file against /tmp cleaners
6cb03e
+ *		TouchSocketFiles	- Protect socket files against /tmp cleaners
6cb03e
  *		pq_init			- initialize libpq at backend startup
6cb03e
  *		pq_comm_reset	- reset libpq during error recovery
6cb03e
  *		pq_close		- shutdown libpq at backend exit
6cb03e
@@ -103,8 +103,8 @@ int			Unix_socket_permissions;
6cb03e
 char	   *Unix_socket_group;
6cb03e
 
6cb03e
 
6cb03e
-/* Where the Unix socket file is */
6cb03e
-static char sock_path[MAXPGPATH];
6cb03e
+/* Where the Unix socket files are (list of palloc'd strings) */
6cb03e
+static List *sock_paths = NIL;
6cb03e
 
6cb03e
 
6cb03e
 /*
6cb03e
@@ -141,8 +141,8 @@ static int	internal_flush(void);
6cb03e
 static void pq_set_nonblocking(bool nonblocking);
6cb03e
 
6cb03e
 #ifdef HAVE_UNIX_SOCKETS
6cb03e
-static int	Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName);
6cb03e
-static int	Setup_AF_UNIX(void);
6cb03e
+static int	Lock_AF_UNIX(char *unixSocketDir, char *unixSocketPath);
6cb03e
+static int	Setup_AF_UNIX(char *sock_path);
6cb03e
 #endif   /* HAVE_UNIX_SOCKETS */
6cb03e
 
6cb03e
 
6cb03e
@@ -236,29 +236,43 @@ pq_close(int code, Datum arg)
6cb03e
 
6cb03e
 /* StreamDoUnlink()
6cb03e
  * Shutdown routine for backend connection
6cb03e
- * If a Unix socket is used for communication, explicitly close it.
6cb03e
+ * If any Unix sockets are used for communication, explicitly close them.
6cb03e
  */
6cb03e
 #ifdef HAVE_UNIX_SOCKETS
6cb03e
 static void
6cb03e
 StreamDoUnlink(int code, Datum arg)
6cb03e
 {
6cb03e
-	Assert(sock_path[0]);
6cb03e
-	unlink(sock_path);
6cb03e
+	ListCell   *l;
6cb03e
+
6cb03e
+	/* Loop through all created sockets... */
6cb03e
+	foreach(l, sock_paths)
6cb03e
+	{
6cb03e
+		char	   *sock_path = (char *) lfirst(l);
6cb03e
+
6cb03e
+		unlink(sock_path);
6cb03e
+	}
6cb03e
+	/* Since we're about to exit, no need to reclaim storage */
6cb03e
+	sock_paths = NIL;
6cb03e
 }
6cb03e
 #endif   /* HAVE_UNIX_SOCKETS */
6cb03e
 
6cb03e
 /*
6cb03e
  * StreamServerPort -- open a "listening" port to accept connections.
6cb03e
  *
6cb03e
- * Successfully opened sockets are added to the ListenSocket[] array,
6cb03e
- * at the first position that isn't PGINVALID_SOCKET.
6cb03e
+ * family should be AF_UNIX or AF_UNSPEC; portNumber is the port number.
6cb03e
+ * For AF_UNIX ports, hostName should be NULL and unixSocketDir must be
6cb03e
+ * specified.  For TCP ports, hostName is either NULL for all interfaces or
6cb03e
+ * the interface to listen on, and unixSocketDir is ignored (can be NULL).
6cb03e
+ *
6cb03e
+ * Successfully opened sockets are added to the ListenSocket[] array (of
6cb03e
+ * length MaxListen), at the first position that isn't PGINVALID_SOCKET.
6cb03e
  *
6cb03e
  * RETURNS: STATUS_OK or STATUS_ERROR
6cb03e
  */
6cb03e
 
6cb03e
 int
6cb03e
 StreamServerPort(int family, char *hostName, unsigned short portNumber,
6cb03e
-				 char *unixSocketName,
6cb03e
+				 char *unixSocketDir,
6cb03e
 				 pgsocket ListenSocket[], int MaxListen)
6cb03e
 {
6cb03e
 	pgsocket	fd;
6cb03e
@@ -275,6 +289,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
6cb03e
 	int			listen_index = 0;
6cb03e
 	int			added = 0;
6cb03e
 
6cb03e
+#ifdef HAVE_UNIX_SOCKETS
6cb03e
+	char		unixSocketPath[MAXPGPATH];
6cb03e
+#endif
6cb03e
 #if !defined(WIN32) || defined(IPV6_V6ONLY)
6cb03e
 	int			one = 1;
6cb03e
 #endif
6cb03e
@@ -288,10 +305,22 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
6cb03e
 #ifdef HAVE_UNIX_SOCKETS
6cb03e
 	if (family == AF_UNIX)
6cb03e
 	{
6cb03e
-		/* Lock_AF_UNIX will also fill in sock_path. */
6cb03e
-		if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK)
6cb03e
+		/*
6cb03e
+		 * Create unixSocketPath from portNumber and unixSocketDir and lock
6cb03e
+		 * that file path
6cb03e
+		 */
6cb03e
+		UNIXSOCK_PATH(unixSocketPath, portNumber, unixSocketDir);
6cb03e
+		if (strlen(unixSocketPath) >= UNIXSOCK_PATH_BUFLEN)
6cb03e
+		{
6cb03e
+			ereport(LOG,
6cb03e
+					(errmsg("Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
6cb03e
+							unixSocketPath,
6cb03e
+							(int) (UNIXSOCK_PATH_BUFLEN - 1))));
6cb03e
 			return STATUS_ERROR;
6cb03e
-		service = sock_path;
6cb03e
+		}
6cb03e
+		if (Lock_AF_UNIX(unixSocketDir, unixSocketPath) != STATUS_OK)
6cb03e
+			return STATUS_ERROR;
6cb03e
+		service = unixSocketPath;
6cb03e
 	}
6cb03e
 	else
6cb03e
 #endif   /* HAVE_UNIX_SOCKETS */
6cb03e
@@ -434,7 +463,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
6cb03e
 					 (IS_AF_UNIX(addr->ai_family)) ?
6cb03e
 				  errhint("Is another postmaster already running on port %d?"
6cb03e
 						  " If not, remove socket file \"%s\" and retry.",
6cb03e
-						  (int) portNumber, sock_path) :
6cb03e
+						  (int) portNumber, service) :
6cb03e
 				  errhint("Is another postmaster already running on port %d?"
6cb03e
 						  " If not, wait a few seconds and retry.",
6cb03e
 						  (int) portNumber)));
6cb03e
@@ -445,7 +474,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
6cb03e
 #ifdef HAVE_UNIX_SOCKETS
6cb03e
 		if (addr->ai_family == AF_UNIX)
6cb03e
 		{
6cb03e
-			if (Setup_AF_UNIX() != STATUS_OK)
6cb03e
+			if (Setup_AF_UNIX(service) != STATUS_OK)
6cb03e
 			{
6cb03e
 				closesocket(fd);
6cb03e
 				break;
6cb03e
@@ -492,18 +521,8 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
6cb03e
  * Lock_AF_UNIX -- configure unix socket file path
6cb03e
  */
6cb03e
 static int
6cb03e
-Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
6cb03e
+Lock_AF_UNIX(char *unixSocketDir, char *unixSocketPath)
6cb03e
 {
6cb03e
-	UNIXSOCK_PATH(sock_path, portNumber, unixSocketName);
6cb03e
-	if (strlen(sock_path) >= UNIXSOCK_PATH_BUFLEN)
6cb03e
-	{
6cb03e
-		ereport(LOG,
6cb03e
-				(errmsg("Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
6cb03e
-						sock_path,
6cb03e
-						(int) (UNIXSOCK_PATH_BUFLEN - 1))));
6cb03e
-		return STATUS_ERROR;
6cb03e
-	}
6cb03e
-
6cb03e
 	/*
6cb03e
 	 * Grab an interlock file associated with the socket file.
6cb03e
 	 *
6cb03e
@@ -512,13 +531,23 @@ Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
6cb03e
 	 * more portable, and second, it lets us remove any pre-existing socket
6cb03e
 	 * file without race conditions.
6cb03e
 	 */
6cb03e
-	CreateSocketLockFile(sock_path, true);
6cb03e
+	CreateSocketLockFile(unixSocketPath, true, unixSocketDir);
6cb03e
 
6cb03e
 	/*
6cb03e
 	 * Once we have the interlock, we can safely delete any pre-existing
6cb03e
 	 * socket file to avoid failure at bind() time.
6cb03e
 	 */
6cb03e
-	unlink(sock_path);
6cb03e
+	unlink(unixSocketPath);
6cb03e
+
6cb03e
+	/*
6cb03e
+	 * Arrange to unlink the socket file(s) at proc_exit.  If this is the
6cb03e
+	 * first one, set up the on_proc_exit function to do it; then add this
6cb03e
+	 * socket file to the list of files to unlink.
6cb03e
+	 */
6cb03e
+	if (sock_paths == NIL)
6cb03e
+		on_proc_exit(StreamDoUnlink, 0);
6cb03e
+
6cb03e
+	sock_paths = lappend(sock_paths, pstrdup(unixSocketPath));
6cb03e
 
6cb03e
 	return STATUS_OK;
6cb03e
 }
6cb03e
@@ -528,11 +557,8 @@ Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
6cb03e
  * Setup_AF_UNIX -- configure unix socket permissions
6cb03e
  */
6cb03e
 static int
6cb03e
-Setup_AF_UNIX(void)
6cb03e
+Setup_AF_UNIX(char *sock_path)
6cb03e
 {
6cb03e
-	/* Arrange to unlink the socket file at exit */
6cb03e
-	on_proc_exit(StreamDoUnlink, 0);
6cb03e
-
6cb03e
 	/*
6cb03e
 	 * Fix socket ownership/permission if requested.  Note we must do this
6cb03e
 	 * before we listen() to avoid a window where unwanted connections could
6cb03e
@@ -714,20 +740,24 @@ StreamClose(pgsocket sock)
6cb03e
 }
6cb03e
 
6cb03e
 /*
6cb03e
- * TouchSocketFile -- mark socket file as recently accessed
6cb03e
+ * TouchSocketFiles -- mark socket files as recently accessed
6cb03e
  *
6cb03e
  * This routine should be called every so often to ensure that the socket
6cb03e
- * file has a recent mod date (ordinary operations on sockets usually won't
6cb03e
- * change the mod date).  That saves it from being removed by
6cb03e
+ * files have a recent mod date (ordinary operations on sockets usually won't
6cb03e
+ * change the mod date).  That saves them from being removed by
6cb03e
  * overenthusiastic /tmp-directory-cleaner daemons.  (Another reason we should
6cb03e
  * never have put the socket file in /tmp...)
6cb03e
  */
6cb03e
 void
6cb03e
-TouchSocketFile(void)
6cb03e
+TouchSocketFiles(void)
6cb03e
 {
6cb03e
-	/* Do nothing if we did not create a socket... */
6cb03e
-	if (sock_path[0] != '\0')
6cb03e
+	ListCell   *l;
6cb03e
+
6cb03e
+	/* Loop through all created sockets... */
6cb03e
+	foreach(l, sock_paths)
6cb03e
 	{
6cb03e
+		char	   *sock_path = (char *) lfirst(l);
6cb03e
+
6cb03e
 		/*
6cb03e
 		 * utime() is POSIX standard, utimes() is a common alternative. If we
6cb03e
 		 * have neither, there's no way to affect the mod or access time of
6cb03e
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
6cb03e
index 07aca31..e84a18c 100644
6cb03e
--- a/src/backend/postmaster/postmaster.c
6cb03e
+++ b/src/backend/postmaster/postmaster.c
6cb03e
@@ -160,7 +160,9 @@ static Backend *ShmemBackendArray;
6cb03e
 
6cb03e
 /* The socket number we are listening for connections on */
6cb03e
 int			PostPortNumber;
6cb03e
-char	   *UnixSocketDir;
6cb03e
+/* The directory names for Unix socket(s) */
6cb03e
+char	   *Unix_socket_directories;
6cb03e
+/* The TCP listen address(es) */
6cb03e
 char	   *ListenAddresses;
6cb03e
 
6cb03e
 /*
6cb03e
@@ -636,7 +638,7 @@ PostmasterMain(int argc, char *argv[])
6cb03e
 				break;
6cb03e
 
6cb03e
 			case 'k':
6cb03e
-				SetConfigOption("unix_socket_directory", optarg, PGC_POSTMASTER, PGC_S_ARGV);
6cb03e
+				SetConfigOption("unix_socket_directories", optarg, PGC_POSTMASTER, PGC_S_ARGV);
6cb03e
 				break;
6cb03e
 
6cb03e
 			case 'l':
6cb03e
@@ -880,7 +882,7 @@ PostmasterMain(int argc, char *argv[])
6cb03e
 		/* Need a modifiable copy of ListenAddresses */
6cb03e
 		rawstring = pstrdup(ListenAddresses);
6cb03e
 
6cb03e
-		/* Parse string into list of identifiers */
6cb03e
+		/* Parse string into list of hostnames */
6cb03e
 		if (!SplitIdentifierString(rawstring, ',', &elemlist))
6cb03e
 		{
6cb03e
 			/* syntax error in list */
6cb03e
@@ -896,12 +898,12 @@ PostmasterMain(int argc, char *argv[])
6cb03e
 			if (strcmp(curhost, "*") == 0)
6cb03e
 				status = StreamServerPort(AF_UNSPEC, NULL,
6cb03e
 										  (unsigned short) PostPortNumber,
6cb03e
-										  UnixSocketDir,
6cb03e
+										  NULL,
6cb03e
 										  ListenSocket, MAXLISTEN);
6cb03e
 			else
6cb03e
 				status = StreamServerPort(AF_UNSPEC, curhost,
6cb03e
 										  (unsigned short) PostPortNumber,
6cb03e
-										  UnixSocketDir,
6cb03e
+										  NULL,
6cb03e
 										  ListenSocket, MAXLISTEN);
6cb03e
 
6cb03e
 			if (status == STATUS_OK)
6cb03e
@@ -920,7 +922,7 @@ PostmasterMain(int argc, char *argv[])
6cb03e
 								curhost)));
6cb03e
 		}
6cb03e
 
6cb03e
-		if (!success && list_length(elemlist))
6cb03e
+		if (!success && elemlist != NIL)
6cb03e
 			ereport(FATAL,
6cb03e
 					(errmsg("could not create any TCP/IP sockets")));
6cb03e
 
6cb03e
@@ -967,13 +969,54 @@ PostmasterMain(int argc, char *argv[])
6cb03e
 #endif
6cb03e
 
6cb03e
 #ifdef HAVE_UNIX_SOCKETS
6cb03e
-	status = StreamServerPort(AF_UNIX, NULL,
6cb03e
-							  (unsigned short) PostPortNumber,
6cb03e
-							  UnixSocketDir,
6cb03e
-							  ListenSocket, MAXLISTEN);
6cb03e
-	if (status != STATUS_OK)
6cb03e
-		ereport(WARNING,
6cb03e
-				(errmsg("could not create Unix-domain socket")));
6cb03e
+	if (Unix_socket_directories)
6cb03e
+	{
6cb03e
+		char	   *rawstring;
6cb03e
+		List	   *elemlist;
6cb03e
+		ListCell   *l;
6cb03e
+		int			success = 0;
6cb03e
+
6cb03e
+		/* Need a modifiable copy of Unix_socket_directories */
6cb03e
+		rawstring = pstrdup(Unix_socket_directories);
6cb03e
+
6cb03e
+		/* Parse string into list of directories */
6cb03e
+		if (!SplitDirectoriesString(rawstring, ',', &elemlist))
6cb03e
+		{
6cb03e
+			/* syntax error in list */
6cb03e
+			ereport(FATAL,
6cb03e
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
6cb03e
+					 errmsg("invalid list syntax for \"unix_socket_directories\"")));
6cb03e
+		}
6cb03e
+
6cb03e
+		foreach(l, elemlist)
6cb03e
+		{
6cb03e
+			char	   *socketdir = (char *) lfirst(l);
6cb03e
+
6cb03e
+			status = StreamServerPort(AF_UNIX, NULL,
6cb03e
+									  (unsigned short) PostPortNumber,
6cb03e
+									  socketdir,
6cb03e
+									  ListenSocket, MAXLISTEN);
6cb03e
+
6cb03e
+			if (status == STATUS_OK)
6cb03e
+			{
6cb03e
+				success++;
6cb03e
+				/* record the first successful Unix socket in lockfile */
6cb03e
+				if (success == 1)
6cb03e
+					AddToDataDirLockFile(LOCK_FILE_LINE_SOCKET_DIR, socketdir);
6cb03e
+			}
6cb03e
+			else
6cb03e
+				ereport(WARNING,
6cb03e
+						(errmsg("could not create Unix-domain socket in directory \"%s\"",
6cb03e
+								socketdir)));
6cb03e
+		}
6cb03e
+
6cb03e
+		if (!success && elemlist != NIL)
6cb03e
+			ereport(FATAL,
6cb03e
+					(errmsg("could not create any Unix-domain sockets")));
6cb03e
+
6cb03e
+		list_free_deep(elemlist);
6cb03e
+		pfree(rawstring);
6cb03e
+	}
6cb03e
 #endif
6cb03e
 
6cb03e
 	/*
6cb03e
@@ -1561,14 +1604,14 @@ ServerLoop(void)
6cb03e
 		}
6cb03e
 
6cb03e
 		/*
6cb03e
-		 * Touch Unix socket and lock file every 58 minutes, to ensure that
6cb03e
+		 * Touch Unix socket and lock files every 58 minutes, to ensure that
6cb03e
 		 * they are not removed by overzealous /tmp-cleaning tasks.  We assume
6cb03e
 		 * no one runs cleaners with cutoff times of less than an hour ...
6cb03e
 		 */
6cb03e
 		if (now - last_touch_time >= 58 * SECS_PER_MINUTE)
6cb03e
 		{
6cb03e
-			TouchSocketFile();
6cb03e
-			TouchSocketLockFile();
6cb03e
+			TouchSocketFiles();
6cb03e
+			TouchSocketLockFiles();
6cb03e
 			last_touch_time = now;
6cb03e
 		}
6cb03e
 	}
6cb03e
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
6cb03e
index 39017ff..318ac38 100644
6cb03e
--- a/src/backend/tcop/postgres.c
6cb03e
+++ b/src/backend/tcop/postgres.c
6cb03e
@@ -3393,7 +3393,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx,
6cb03e
 				break;
6cb03e
 
6cb03e
 			case 'k':
6cb03e
-				SetConfigOption("unix_socket_directory", optarg, ctx, gucsource);
6cb03e
+				SetConfigOption("unix_socket_directories", optarg, ctx, gucsource);
6cb03e
 				break;
6cb03e
 
6cb03e
 			case 'l':
6cb03e
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
6cb03e
index d4abfe3..e8217ac 100644
6cb03e
--- a/src/backend/utils/adt/varlena.c
6cb03e
+++ b/src/backend/utils/adt/varlena.c
6cb03e
@@ -2446,6 +2446,119 @@ SplitIdentifierString(char *rawstring, char separator,
6cb03e
 }
6cb03e
 
6cb03e
 
6cb03e
+/*
6cb03e
+ * SplitDirectoriesString --- parse a string containing directory names
6cb03e
+ *
6cb03e
+ * This is similar to SplitIdentifierString, except that the parsing
6cb03e
+ * rules are meant to handle pathnames instead of identifiers: there is
6cb03e
+ * no downcasing, embedded spaces are allowed, the max length is MAXPGPATH-1,
6cb03e
+ * and we apply canonicalize_path() to each extracted string.  Because of the
6cb03e
+ * last, the returned strings are separately palloc'd rather than being
6cb03e
+ * pointers into rawstring --- but we still scribble on rawstring.
6cb03e
+ *
6cb03e
+ * Inputs:
6cb03e
+ *	rawstring: the input string; must be modifiable!
6cb03e
+ *	separator: the separator punctuation expected between directories
6cb03e
+ *			   (typically ',' or ';').	Whitespace may also appear around
6cb03e
+ *			   directories.
6cb03e
+ * Outputs:
6cb03e
+ *	namelist: filled with a palloc'd list of directory names.
6cb03e
+ *			  Caller should list_free_deep() this even on error return.
6cb03e
+ *
6cb03e
+ * Returns TRUE if okay, FALSE if there is a syntax error in the string.
6cb03e
+ *
6cb03e
+ * Note that an empty string is considered okay here.
6cb03e
+ */
6cb03e
+bool
6cb03e
+SplitDirectoriesString(char *rawstring, char separator,
6cb03e
+					   List **namelist)
6cb03e
+{
6cb03e
+	char	   *nextp = rawstring;
6cb03e
+	bool		done = false;
6cb03e
+
6cb03e
+	*namelist = NIL;
6cb03e
+
6cb03e
+	while (isspace((unsigned char) *nextp))
6cb03e
+		nextp++;				/* skip leading whitespace */
6cb03e
+
6cb03e
+	if (*nextp == '\0')
6cb03e
+		return true;			/* allow empty string */
6cb03e
+
6cb03e
+	/* At the top of the loop, we are at start of a new directory. */
6cb03e
+	do
6cb03e
+	{
6cb03e
+		char	   *curname;
6cb03e
+		char	   *endp;
6cb03e
+
6cb03e
+		if (*nextp == '\"')
6cb03e
+		{
6cb03e
+			/* Quoted name --- collapse quote-quote pairs */
6cb03e
+			curname = nextp + 1;
6cb03e
+			for (;;)
6cb03e
+			{
6cb03e
+				endp = strchr(nextp + 1, '\"');
6cb03e
+				if (endp == NULL)
6cb03e
+					return false;		/* mismatched quotes */
6cb03e
+				if (endp[1] != '\"')
6cb03e
+					break;		/* found end of quoted name */
6cb03e
+				/* Collapse adjacent quotes into one quote, and look again */
6cb03e
+				memmove(endp, endp + 1, strlen(endp));
6cb03e
+				nextp = endp;
6cb03e
+			}
6cb03e
+			/* endp now points at the terminating quote */
6cb03e
+			nextp = endp + 1;
6cb03e
+		}
6cb03e
+		else
6cb03e
+		{
6cb03e
+			/* Unquoted name --- extends to separator or end of string */
6cb03e
+			curname = endp = nextp;
6cb03e
+			while (*nextp && *nextp != separator)
6cb03e
+			{
6cb03e
+				/* trailing whitespace should not be included in name */
6cb03e
+				if (!isspace((unsigned char) *nextp))
6cb03e
+					endp = nextp + 1;
6cb03e
+				nextp++;
6cb03e
+			}
6cb03e
+			if (curname == endp)
6cb03e
+				return false;	/* empty unquoted name not allowed */
6cb03e
+		}
6cb03e
+
6cb03e
+		while (isspace((unsigned char) *nextp))
6cb03e
+			nextp++;			/* skip trailing whitespace */
6cb03e
+
6cb03e
+		if (*nextp == separator)
6cb03e
+		{
6cb03e
+			nextp++;
6cb03e
+			while (isspace((unsigned char) *nextp))
6cb03e
+				nextp++;		/* skip leading whitespace for next */
6cb03e
+			/* we expect another name, so done remains false */
6cb03e
+		}
6cb03e
+		else if (*nextp == '\0')
6cb03e
+			done = true;
6cb03e
+		else
6cb03e
+			return false;		/* invalid syntax */
6cb03e
+
6cb03e
+		/* Now safe to overwrite separator with a null */
6cb03e
+		*endp = '\0';
6cb03e
+
6cb03e
+		/* Truncate path if it's overlength */
6cb03e
+		if (strlen(curname) >= MAXPGPATH)
6cb03e
+			curname[MAXPGPATH - 1] = '\0';
6cb03e
+
6cb03e
+		/*
6cb03e
+		 * Finished isolating current name --- add it to list
6cb03e
+		 */
6cb03e
+		curname = pstrdup(curname);
6cb03e
+		canonicalize_path(curname);
6cb03e
+		*namelist = lappend(*namelist, curname);
6cb03e
+
6cb03e
+		/* Loop back if we didn't reach end of string */
6cb03e
+	} while (!done);
6cb03e
+
6cb03e
+	return true;
6cb03e
+}
6cb03e
+
6cb03e
+
6cb03e
 /*****************************************************************************
6cb03e
  *	Comparison Functions used for bytea
6cb03e
  *
6cb03e
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
6cb03e
index f994af6..db5303c 100644
6cb03e
--- a/src/backend/utils/init/miscinit.c
6cb03e
+++ b/src/backend/utils/init/miscinit.c
6cb03e
@@ -49,8 +49,8 @@
6cb03e
 
6cb03e
 ProcessingMode Mode = InitProcessing;
6cb03e
 
6cb03e
-/* Note: we rely on this to initialize as zeroes */
6cb03e
-static char socketLockFile[MAXPGPATH];
6cb03e
+/* List of lock files to be removed at proc exit */
6cb03e
+static List *lock_files = NIL;
6cb03e
 
6cb03e
 
6cb03e
 /* ----------------------------------------------------------------
6cb03e
@@ -640,32 +640,35 @@ GetUserNameFromId(Oid roleid)
6cb03e
  */
6cb03e
 
6cb03e
 /*
6cb03e
- * proc_exit callback to remove a lockfile.
6cb03e
+ * proc_exit callback to remove lockfiles.
6cb03e
  */
6cb03e
 static void
6cb03e
-UnlinkLockFile(int status, Datum filename)
6cb03e
+UnlinkLockFiles(int status, Datum arg)
6cb03e
 {
6cb03e
-	char	   *fname = (char *) DatumGetPointer(filename);
6cb03e
+	ListCell   *l;
6cb03e
 
6cb03e
-	if (fname != NULL)
6cb03e
+	foreach(l, lock_files)
6cb03e
 	{
6cb03e
-		if (unlink(fname) != 0)
6cb03e
-		{
6cb03e
-			/* Should we complain if the unlink fails? */
6cb03e
-		}
6cb03e
-		free(fname);
6cb03e
+		char	   *curfile = (char *) lfirst(l);
6cb03e
+
6cb03e
+		unlink(curfile);
6cb03e
+		/* Should we complain if the unlink fails? */
6cb03e
 	}
6cb03e
+	/* Since we're about to exit, no need to reclaim storage */
6cb03e
+	lock_files = NIL;
6cb03e
 }
6cb03e
 
6cb03e
 /*
6cb03e
  * Create a lockfile.
6cb03e
  *
6cb03e
- * filename is the name of the lockfile to create.
6cb03e
+ * filename is the path name of the lockfile to create.
6cb03e
  * amPostmaster is used to determine how to encode the output PID.
6cb03e
+ * socketDir is the Unix socket directory path to include (possibly empty).
6cb03e
  * isDDLock and refName are used to determine what error message to produce.
6cb03e
  */
6cb03e
 static void
6cb03e
 CreateLockFile(const char *filename, bool amPostmaster,
6cb03e
+			   const char *socketDir,
6cb03e
 			   bool isDDLock, const char *refName)
6cb03e
 {
6cb03e
 	int			fd;
6cb03e
@@ -891,12 +894,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
6cb03e
 			 DataDir,
6cb03e
 			 (long) MyStartTime,
6cb03e
 			 PostPortNumber,
6cb03e
-#ifdef HAVE_UNIX_SOCKETS
6cb03e
-			 (*UnixSocketDir != '\0') ? UnixSocketDir : DEFAULT_PGSOCKET_DIR
6cb03e
-#else
6cb03e
-			 ""
6cb03e
-#endif
6cb03e
-		);
6cb03e
+			 socketDir);
6cb03e
 
6cb03e
 	/*
6cb03e
 	 * In a standalone backend, the next line (LOCK_FILE_LINE_LISTEN_ADDR)
6cb03e
@@ -941,9 +939,14 @@ CreateLockFile(const char *filename, bool amPostmaster,
6cb03e
 	}
6cb03e
 
6cb03e
 	/*
6cb03e
-	 * Arrange for automatic removal of lockfile at proc_exit.
6cb03e
+	 * Arrange to unlink the lock file(s) at proc_exit.  If this is the
6cb03e
+	 * first one, set up the on_proc_exit function to do it; then add this
6cb03e
+	 * lock file to the list of files to unlink.
6cb03e
 	 */
6cb03e
-	on_proc_exit(UnlinkLockFile, PointerGetDatum(strdup(filename)));
6cb03e
+	if (lock_files == NIL)
6cb03e
+		on_proc_exit(UnlinkLockFiles, 0);
6cb03e
+
6cb03e
+	lock_files = lappend(lock_files, pstrdup(filename));
6cb03e
 }
6cb03e
 
6cb03e
 /*
6cb03e
@@ -952,41 +955,50 @@ CreateLockFile(const char *filename, bool amPostmaster,
6cb03e
  * When this is called, we must have already switched the working
6cb03e
  * directory to DataDir, so we can just use a relative path.  This
6cb03e
  * helps ensure that we are locking the directory we should be.
6cb03e
+ *
6cb03e
+ * Note that the socket directory path line is initially written as empty.
6cb03e
+ * postmaster.c will rewrite it upon creating the first Unix socket.
6cb03e
  */
6cb03e
 void
6cb03e
 CreateDataDirLockFile(bool amPostmaster)
6cb03e
 {
6cb03e
-	CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, true, DataDir);
6cb03e
+	CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, "", true, DataDir);
6cb03e
 }
6cb03e
 
6cb03e
 /*
6cb03e
  * Create a lockfile for the specified Unix socket file.
6cb03e
  */
6cb03e
 void
6cb03e
-CreateSocketLockFile(const char *socketfile, bool amPostmaster)
6cb03e
+CreateSocketLockFile(const char *socketfile, bool amPostmaster,
6cb03e
+					 const char *socketDir)
6cb03e
 {
6cb03e
 	char		lockfile[MAXPGPATH];
6cb03e
 
6cb03e
 	snprintf(lockfile, sizeof(lockfile), "%s.lock", socketfile);
6cb03e
-	CreateLockFile(lockfile, amPostmaster, false, socketfile);
6cb03e
-	/* Save name of lockfile for TouchSocketLockFile */
6cb03e
-	strcpy(socketLockFile, lockfile);
6cb03e
+	CreateLockFile(lockfile, amPostmaster, socketDir, false, socketfile);
6cb03e
 }
6cb03e
 
6cb03e
 /*
6cb03e
- * TouchSocketLockFile -- mark socket lock file as recently accessed
6cb03e
+ * TouchSocketLockFiles -- mark socket lock files as recently accessed
6cb03e
  *
6cb03e
- * This routine should be called every so often to ensure that the lock file
6cb03e
- * has a recent mod or access date.  That saves it
6cb03e
+ * This routine should be called every so often to ensure that the socket
6cb03e
+ * lock files have a recent mod or access date.  That saves them
6cb03e
  * from being removed by overenthusiastic /tmp-directory-cleaner daemons.
6cb03e
  * (Another reason we should never have put the socket file in /tmp...)
6cb03e
  */
6cb03e
 void
6cb03e
-TouchSocketLockFile(void)
6cb03e
+TouchSocketLockFiles(void)
6cb03e
 {
6cb03e
-	/* Do nothing if we did not create a socket... */
6cb03e
-	if (socketLockFile[0] != '\0')
6cb03e
+	ListCell   *l;
6cb03e
+
6cb03e
+	foreach(l, lock_files)
6cb03e
 	{
6cb03e
+		char	   *socketLockFile = (char *) lfirst(l);
6cb03e
+
6cb03e
+		/* No need to touch the data directory lock file, we trust */
6cb03e
+		if (strcmp(socketLockFile, DIRECTORY_LOCK_FILE) == 0)
6cb03e
+			continue;
6cb03e
+
6cb03e
 		/*
6cb03e
 		 * utime() is POSIX standard, utimes() is a common alternative; if we
6cb03e
 		 * have neither, fall back to actually reading the file (which only
6cb03e
@@ -1018,8 +1030,10 @@ TouchSocketLockFile(void)
6cb03e
  * Add (or replace) a line in the data directory lock file.
6cb03e
  * The given string should not include a trailing newline.
6cb03e
  *
6cb03e
- * Caution: this erases all following lines.  In current usage that is OK
6cb03e
- * because lines are added in order.  We could improve it if needed.
6cb03e
+ * Note: because we don't truncate the file, if we were to rewrite a line
6cb03e
+ * with less data than it had before, there would be garbage after the last
6cb03e
+ * line.  We don't ever actually do that, so not worth adding another kernel
6cb03e
+ * call to cover the possibility.
6cb03e
  */
6cb03e
 void
6cb03e
 AddToDataDirLockFile(int target_line, const char *str)
6cb03e
@@ -1027,8 +1041,10 @@ AddToDataDirLockFile(int target_line, const char *str)
6cb03e
 	int			fd;
6cb03e
 	int			len;
6cb03e
 	int			lineno;
6cb03e
-	char	   *ptr;
6cb03e
-	char		buffer[BLCKSZ];
6cb03e
+	char	   *srcptr;
6cb03e
+	char	   *destptr;
6cb03e
+	char		srcbuffer[BLCKSZ];
6cb03e
+	char		destbuffer[BLCKSZ];
6cb03e
 
6cb03e
 	fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0);
6cb03e
 	if (fd < 0)
6cb03e
@@ -1039,7 +1055,7 @@ AddToDataDirLockFile(int target_line, const char *str)
6cb03e
 						DIRECTORY_LOCK_FILE)));
6cb03e
 		return;
6cb03e
 	}
6cb03e
-	len = read(fd, buffer, sizeof(buffer) - 1);
6cb03e
+	len = read(fd, srcbuffer, sizeof(srcbuffer) - 1);
6cb03e
 	if (len < 0)
6cb03e
 	{
6cb03e
 		ereport(LOG,
6cb03e
@@ -1049,37 +1065,51 @@ AddToDataDirLockFile(int target_line, const char *str)
6cb03e
 		close(fd);
6cb03e
 		return;
6cb03e
 	}
6cb03e
-	buffer[len] = '\0';
6cb03e
+	srcbuffer[len] = '\0';
6cb03e
 
6cb03e
 	/*
6cb03e
-	 * Skip over lines we are not supposed to rewrite.
6cb03e
+	 * Advance over lines we are not supposed to rewrite, then copy them
6cb03e
+	 * to destbuffer.
6cb03e
 	 */
6cb03e
-	ptr = buffer;
6cb03e
+	srcptr = srcbuffer;
6cb03e
 	for (lineno = 1; lineno < target_line; lineno++)
6cb03e
 	{
6cb03e
-		if ((ptr = strchr(ptr, '\n')) == NULL)
6cb03e
+		if ((srcptr = strchr(srcptr, '\n')) == NULL)
6cb03e
 		{
6cb03e
 			elog(LOG, "incomplete data in \"%s\": found only %d newlines while trying to add line %d",
6cb03e
 				 DIRECTORY_LOCK_FILE, lineno - 1, target_line);
6cb03e
 			close(fd);
6cb03e
 			return;
6cb03e
 		}
6cb03e
-		ptr++;
6cb03e
+		srcptr++;
6cb03e
 	}
6cb03e
+	memcpy(destbuffer, srcbuffer, srcptr - srcbuffer);
6cb03e
+	destptr = destbuffer + (srcptr - srcbuffer);
6cb03e
 
6cb03e
 	/*
6cb03e
 	 * Write or rewrite the target line.
6cb03e
 	 */
6cb03e
-	snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s\n", str);
6cb03e
+	snprintf(destptr, destbuffer + sizeof(destbuffer) - destptr, "%s\n", str);
6cb03e
+	destptr += strlen(destptr);
6cb03e
+
6cb03e
+	/*
6cb03e
+	 * If there are more lines in the old file, append them to destbuffer.
6cb03e
+	 */
6cb03e
+	if ((srcptr = strchr(srcptr, '\n')) != NULL)
6cb03e
+	{
6cb03e
+		srcptr++;
6cb03e
+		snprintf(destptr, destbuffer + sizeof(destbuffer) - destptr, "%s",
6cb03e
+				 srcptr);
6cb03e
+	}
6cb03e
 
6cb03e
 	/*
6cb03e
 	 * And rewrite the data.  Since we write in a single kernel call, this
6cb03e
 	 * update should appear atomic to onlookers.
6cb03e
 	 */
6cb03e
-	len = strlen(buffer);
6cb03e
+	len = strlen(destbuffer);
6cb03e
 	errno = 0;
6cb03e
 	if (lseek(fd, (off_t) 0, SEEK_SET) != 0 ||
6cb03e
-		(int) write(fd, buffer, len) != len)
6cb03e
+		(int) write(fd, destbuffer, len) != len)
6cb03e
 	{
6cb03e
 		/* if write didn't set errno, assume problem is no disk space */
6cb03e
 		if (errno == 0)
6cb03e
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
6cb03e
index e5ee0f8..1428cb6 100644
6cb03e
--- a/src/backend/utils/misc/guc.c
6cb03e
+++ b/src/backend/utils/misc/guc.c
6cb03e
@@ -2894,14 +2894,18 @@ static struct config_string ConfigureNamesString[] =
6cb03e
 	},
6cb03e
 
6cb03e
 	{
6cb03e
-		{"unix_socket_directory", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
6cb03e
-			gettext_noop("Sets the directory where the Unix-domain socket will be created."),
6cb03e
+		{"unix_socket_directories", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
6cb03e
+			gettext_noop("Sets the directories where Unix-domain sockets will be created."),
6cb03e
 			NULL,
6cb03e
 			GUC_SUPERUSER_ONLY
6cb03e
 		},
6cb03e
-		&UnixSocketDir,
6cb03e
+		&Unix_socket_directories,
6cb03e
+#ifdef HAVE_UNIX_SOCKETS
6cb03e
+		DEFAULT_PGSOCKET_DIR,
6cb03e
+#else
6cb03e
 		"",
6cb03e
-		check_canonical_path, NULL, NULL
6cb03e
+#endif
6cb03e
+		NULL, NULL, NULL
6cb03e
 	},
6cb03e
 
6cb03e
 	{
6cb03e
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
6cb03e
index 013a91a..c0ab61c 100644
6cb03e
--- a/src/backend/utils/misc/postgresql.conf.sample
6cb03e
+++ b/src/backend/utils/misc/postgresql.conf.sample
6cb03e
@@ -67,7 +67,8 @@
6cb03e
 # Note:  Increasing max_connections costs ~400 bytes of shared memory per
6cb03e
 # connection slot, plus lock space (see max_locks_per_transaction).
6cb03e
 #superuser_reserved_connections = 3	# (change requires restart)
6cb03e
-#unix_socket_directory = ''		# (change requires restart)
6cb03e
+#unix_socket_directories = '/tmp'	# comma-separated list of directories
6cb03e
+					# (change requires restart)
6cb03e
 #unix_socket_group = ''			# (change requires restart)
6cb03e
 #unix_socket_permissions = 0777		# begin with 0 to use octal notation
6cb03e
 					# (change requires restart)
6cb03e
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
6cb03e
index 23fa468..452ac0b 100644
6cb03e
--- a/src/bin/initdb/initdb.c
6cb03e
+++ b/src/bin/initdb/initdb.c
6cb03e
@@ -991,7 +991,7 @@ static void
6cb03e
 setup_config(void)
6cb03e
 {
6cb03e
 	char	  **conflines;
6cb03e
-	char		repltok[TZ_STRLEN_MAX + 100];
6cb03e
+	char		repltok[MAXPGPATH];
6cb03e
 	char		path[MAXPGPATH];
6cb03e
 	const char *default_timezone;
6cb03e
 
6cb03e
@@ -1013,6 +1013,15 @@ setup_config(void)
6cb03e
 				 n_buffers * (BLCKSZ / 1024));
6cb03e
 	conflines = replace_token(conflines, "#shared_buffers = 32MB", repltok);
6cb03e
 
6cb03e
+#ifdef HAVE_UNIX_SOCKETS
6cb03e
+	snprintf(repltok, sizeof(repltok), "#unix_socket_directories = '%s'",
6cb03e
+			 DEFAULT_PGSOCKET_DIR);
6cb03e
+#else
6cb03e
+	snprintf(repltok, sizeof(repltok), "#unix_socket_directories = ''");
6cb03e
+#endif
6cb03e
+	conflines = replace_token(conflines, "#unix_socket_directories = '/tmp'",
6cb03e
+							  repltok);
6cb03e
+
6cb03e
 #if DEF_PGPORT != 5432
6cb03e
 	snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT);
6cb03e
 	conflines = replace_token(conflines, "#port = 5432", repltok);
6cb03e
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
6cb03e
index 66ef6bd..b815ef2 100644
6cb03e
--- a/src/bin/pg_ctl/pg_ctl.c
6cb03e
+++ b/src/bin/pg_ctl/pg_ctl.c
6cb03e
@@ -561,7 +561,7 @@ test_postmaster_connection(bool do_checkpoint)
6cb03e
 						hostaddr = optlines[LOCK_FILE_LINE_LISTEN_ADDR - 1];
6cb03e
 
6cb03e
 						/*
6cb03e
-						 * While unix_socket_directory can accept relative
6cb03e
+						 * While unix_socket_directories can accept relative
6cb03e
 						 * directories, libpq's host parameter must have a
6cb03e
 						 * leading slash to indicate a socket directory.  So,
6cb03e
 						 * ignore sockdir if it's relative, and try to use TCP
6cb03e
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
6cb03e
index 6dd91ba..2bfec2b 100644
6cb03e
--- a/src/include/libpq/libpq.h
6cb03e
+++ b/src/include/libpq/libpq.h
6cb03e
@@ -44,12 +44,12 @@ typedef struct
6cb03e
 /*
6cb03e
  * prototypes for functions in pqcomm.c
6cb03e
  */
6cb03e
-extern int StreamServerPort(int family, char *hostName,
6cb03e
-	unsigned short portNumber, char *unixSocketName, pgsocket ListenSocket[],
6cb03e
-				 int MaxListen);
6cb03e
+extern int	StreamServerPort(int family, char *hostName,
6cb03e
+				 unsigned short portNumber, char *unixSocketDir,
6cb03e
+				 pgsocket ListenSocket[], int MaxListen);
6cb03e
 extern int	StreamConnection(pgsocket server_fd, Port *port);
6cb03e
 extern void StreamClose(pgsocket sock);
6cb03e
-extern void TouchSocketFile(void);
6cb03e
+extern void TouchSocketFiles(void);
6cb03e
 extern void pq_init(void);
6cb03e
 extern void pq_comm_reset(void);
6cb03e
 extern int	pq_getbytes(char *s, size_t len);
6cb03e
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
6cb03e
index 1051ca4..e6c663c 100644
6cb03e
--- a/src/include/miscadmin.h
6cb03e
+++ b/src/include/miscadmin.h
6cb03e
@@ -424,7 +424,7 @@ extern char *local_preload_libraries_string;
6cb03e
  *		2	data directory path
6cb03e
  *		3	postmaster start timestamp (time_t representation)
6cb03e
  *		4	port number
6cb03e
- *		5	socket directory path (empty on Windows)
6cb03e
+ *		5	first Unix socket directory path (empty if none)
6cb03e
  *		6	first listen_address (IP address or "*"; empty if no TCP port)
6cb03e
  *		7	shared memory key (not present on Windows)
6cb03e
  *
6cb03e
@@ -443,8 +443,9 @@ extern char *local_preload_libraries_string;
6cb03e
 #define LOCK_FILE_LINE_SHMEM_KEY	7
6cb03e
 
6cb03e
 extern void CreateDataDirLockFile(bool amPostmaster);
6cb03e
-extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster);
6cb03e
-extern void TouchSocketLockFile(void);
6cb03e
+extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster,
6cb03e
+					 const char *socketDir);
6cb03e
+extern void TouchSocketLockFiles(void);
6cb03e
 extern void AddToDataDirLockFile(int target_line, const char *str);
6cb03e
 extern bool RecheckDataDirLockFile(void);
6cb03e
 extern void ValidatePgVersion(const char *path);
6cb03e
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
6cb03e
index 683ce3c..080a8ca 100644
6cb03e
--- a/src/include/postmaster/postmaster.h
6cb03e
+++ b/src/include/postmaster/postmaster.h
6cb03e
@@ -19,7 +19,7 @@ extern int	ReservedBackends;
6cb03e
 extern int	PostPortNumber;
6cb03e
 extern int	Unix_socket_permissions;
6cb03e
 extern char *Unix_socket_group;
6cb03e
-extern char *UnixSocketDir;
6cb03e
+extern char *Unix_socket_directories;
6cb03e
 extern char *ListenAddresses;
6cb03e
 extern bool ClientAuthInProgress;
6cb03e
 extern int	PreAuthDelay;
6cb03e
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
6cb03e
index 4bf07e4..c830243 100644
6cb03e
--- a/src/include/utils/builtins.h
6cb03e
+++ b/src/include/utils/builtins.h
6cb03e
@@ -754,6 +754,8 @@ extern int	varstr_cmp(char *arg1, int len1, char *arg2, int len2, Oid collid);
6cb03e
 extern List *textToQualifiedNameList(text *textval);
6cb03e
 extern bool SplitIdentifierString(char *rawstring, char separator,
6cb03e
 					  List **namelist);
6cb03e
+extern bool SplitDirectoriesString(char *rawstring, char separator,
6cb03e
+					   List **namelist);
6cb03e
 extern Datum replace_text(PG_FUNCTION_ARGS);
6cb03e
 extern text *replace_text_regexp(text *src_text, void *regexp,
6cb03e
 					text *replace_text, bool glob);
6cb03e
diff --git a/doc/src/sgml/html-stamp b/doc/src/sgml/html-stamp
6cb03e
index e69de29..fcf9276 100644
6cb03e
--- a/doc/src/sgml/html-stamp
6cb03e
+++ b/doc/src/sgml/html-stamp
6cb03e
@@ -0,0 +1 @@
6cb03e
+hack
6cb03e
diff --git a/doc/src/sgml/man-stamp b/doc/src/sgml/man-stamp
6cb03e
index e69de29..fcf9276 100644
6cb03e
--- a/doc/src/sgml/man-stamp
6cb03e
+++ b/doc/src/sgml/man-stamp
6cb03e
@@ -0,0 +1 @@
6cb03e
+hack