On 06/13/2012 03:25 PM, Honza Horak wrote:
Going through the thread, I'd like to sum it up choosing approach with
less potential issues and would like to find a consensus if possible.
It seems unix_socket_directory could be turned into list and probably
renamed to unix_socket_directories, since it would be confusing if a
list value is in singular. On the other hand, we probably don't want to
specify listening ports together with additional unix sockets in one
configuration option, so it seems better to add a new configuration
option to distinguish the primary listening port from additional ports.
Regards,
Honza
A draft patch is attached. It renames unix_socket_directory to
unix_socket_directories and allows to use directory:port to be able to
create more sockets in one directory with different port number in the
socket name.
Regards,
Honza
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index cfdb33a..679c40a 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -838,7 +838,7 @@ omicron bryanh guest1
<varname>unix_socket_permissions</varname> (and possibly
<varname>unix_socket_group</varname>) configuration parameters as
described in <xref linkend="runtime-config-connection">. Or you
- could set the <varname>unix_socket_directory</varname>
+ could set the <varname>unix_socket_directories</varname>
configuration parameter to place the socket file in a suitably
restricted directory.
</para>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 074afee..7634682 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -453,17 +453,23 @@ SET ENABLE_SEQSCAN TO OFF;
</listitem>
</varlistentry>
- <varlistentry id="guc-unix-socket-directory" xreflabel="unix_socket_directory">
- <term><varname>unix_socket_directory</varname> (<type>string</type>)</term>
+ <varlistentry id="guc-unix-socket-directories" xreflabel="unix_socket_directories">
+ <term><varname>unix_socket_directories</varname> (<type>string</type>)</term>
<indexterm>
- <primary><varname>unix_socket_directory</> configuration parameter</primary>
+ <primary><varname>unix_socket_directories</> configuration parameter</primary>
</indexterm>
<listitem>
<para>
- Specifies the directory of the Unix-domain socket on which the
+ Specifies the directories of the Unix-domain sockets on which the
server is to listen for
connections from client applications. The default is normally
<filename>/tmp</filename>, but can be changed at build time.
+ Directories are separated by ',' and additional <replaceable>port</>
+ number can be set, separated from directory by ':'. Port number will
+ only be used as a part of the socket file name. For example,
+ <literal>'/var/run, /tmp:5431'</literal> would create socket files
+ <literal>/var/run/.s.PGSQL.5432</literal> and
+ <literal>/tmp/.s.PGSQL.5431</literal>.
This parameter can only be set at server start.
</para>
@@ -472,7 +478,7 @@ SET ENABLE_SEQSCAN TO OFF;
<literal>.s.PGSQL.<replaceable>nnnn</></literal> where
<replaceable>nnnn</> is the server's port number, an ordinary file
named <literal>.s.PGSQL.<replaceable>nnnn</>.lock</literal> will be
- created in the <varname>unix_socket_directory</> directory. Neither
+ created in the <varname>unix_socket_directories</> directories. Neither
file should ever be removed manually.
</para>
@@ -6593,7 +6599,7 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1)
</row>
<row>
<entry><option>-k <replaceable>x</replaceable></option></entry>
- <entry><literal>unix_socket_directory = <replaceable>x</replaceable></></entry>
+ <entry><literal>unix_socket_directories = <replaceable>x</replaceable></></entry>
</row>
<row>
<entry><option>-l</option></entry>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 7ba18f0..6c74844 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1784,7 +1784,7 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
<para>
The simplest way to prevent spoofing for <literal>local</>
connections is to use a Unix domain socket directory (<xref
- linkend="guc-unix-socket-directory">) that has write permission only
+ linkend="guc-unix-socket-directories">) that has write permission only
for a trusted local user. This prevents a malicious user from creating
their own socket file in that directory. If you are concerned that
some applications might still reference <filename>/tmp</> for the
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index e3ae92d..72505e3 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -349,7 +349,7 @@ AuxiliaryProcessMain(int argc, char *argv[])
/* If standalone, create lockfile for data directory */
if (!IsUnderPostmaster)
- CreateDataDirLockFile(false);
+ CreateDataDirLockFile(false, NULL);
SetProcessingMode(BootstrapProcessing);
IgnoreSystemIndexes = true;
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 5272811..cf1e157 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -103,8 +103,8 @@ int Unix_socket_permissions;
char *Unix_socket_group;
-/* Where the Unix socket file is */
-static char sock_path[MAXPGPATH];
+/* Where the Unix socket files are */
+static List *sock_paths = NIL;
/*
@@ -140,8 +140,8 @@ static int internal_flush(void);
static void pq_set_nonblocking(bool nonblocking);
#ifdef HAVE_UNIX_SOCKETS
-static int Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName);
-static int Setup_AF_UNIX(void);
+static int Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName, char **sock_path);
+static int Setup_AF_UNIX(char *sock_path);
#endif /* HAVE_UNIX_SOCKETS */
@@ -234,14 +234,23 @@ pq_close(int code, Datum arg)
/* StreamDoUnlink()
* Shutdown routine for backend connection
- * If a Unix socket is used for communication, explicitly close it.
+ * If any Unix sockets are used for communication, explicitly close them.
*/
#ifdef HAVE_UNIX_SOCKETS
static void
StreamDoUnlink(int code, Datum arg)
{
- Assert(sock_path[0]);
- unlink(sock_path);
+ ListCell *l;
+ char *cursocket;
+
+ /* Loop through all created sockets... */
+ foreach(l, sock_paths)
+ {
+ cursocket = (char *) lfirst(l);
+ unlink(cursocket);
+ }
+ list_free(sock_paths);
+ sock_paths = NIL;
}
#endif /* HAVE_UNIX_SOCKETS */
@@ -286,10 +295,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
#ifdef HAVE_UNIX_SOCKETS
if (family == AF_UNIX)
{
- /* Lock_AF_UNIX will also fill in sock_path. */
- if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK)
+ /* Lock_AF_UNIX will also fill in service. */
+ if (Lock_AF_UNIX(portNumber, unixSocketName, &service) != STATUS_OK)
return STATUS_ERROR;
- service = sock_path;
}
else
#endif /* HAVE_UNIX_SOCKETS */
@@ -432,7 +440,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
(IS_AF_UNIX(addr->ai_family)) ?
errhint("Is another postmaster already running on port %d?"
" If not, remove socket file \"%s\" and retry.",
- (int) portNumber, sock_path) :
+ (int) portNumber, service) :
errhint("Is another postmaster already running on port %d?"
" If not, wait a few seconds and retry.",
(int) portNumber)));
@@ -443,7 +451,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
#ifdef HAVE_UNIX_SOCKETS
if (addr->ai_family == AF_UNIX)
{
- if (Setup_AF_UNIX() != STATUS_OK)
+ if (Setup_AF_UNIX(service) != STATUS_OK)
{
closesocket(fd);
break;
@@ -490,9 +498,13 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
* Lock_AF_UNIX -- configure unix socket file path
*/
static int
-Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
+Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName, char **sock_path)
{
- UNIXSOCK_PATH(sock_path, portNumber, unixSocketName);
+ char new_sock[MAXPGPATH];
+
+ UNIXSOCK_PATH(new_sock, portNumber, unixSocketName);
+
+ *sock_path = pstrdup(new_sock);
/*
* Grab an interlock file associated with the socket file.
@@ -502,13 +514,14 @@ Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
* more portable, and second, it lets us remove any pre-existing socket
* file without race conditions.
*/
- CreateSocketLockFile(sock_path, true);
+ CreateSocketLockFile(*sock_path, true, unixSocketName);
/*
* Once we have the interlock, we can safely delete any pre-existing
* socket file to avoid failure at bind() time.
*/
- unlink(sock_path);
+ unlink(*sock_path);
+ sock_paths = lappend(sock_paths, *sock_path);
return STATUS_OK;
}
@@ -518,7 +531,7 @@ Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
* Setup_AF_UNIX -- configure unix socket permissions
*/
static int
-Setup_AF_UNIX(void)
+Setup_AF_UNIX(char *sock_path)
{
/* Arrange to unlink the socket file at exit */
on_proc_exit(StreamDoUnlink, 0);
@@ -707,17 +720,21 @@ StreamClose(pgsocket sock)
* TouchSocketFile -- mark socket file as recently accessed
*
* This routine should be called every so often to ensure that the socket
- * file has a recent mod date (ordinary operations on sockets usually won't
- * change the mod date). That saves it from being removed by
+ * files have a recent mod date (ordinary operations on sockets usually won't
+ * change the mod date). That saves them from being removed by
* overenthusiastic /tmp-directory-cleaner daemons. (Another reason we should
- * never have put the socket file in /tmp...)
+ * never have put the socket files in /tmp...)
*/
void
TouchSocketFile(void)
{
- /* Do nothing if we did not create a socket... */
- if (sock_path[0] != '\0')
+ ListCell *l;
+ char *cursocket;
+
+ /* Loop through all created sockets... */
+ foreach(l, sock_paths)
{
+ cursocket = (char *) lfirst(l);
/*
* utime() is POSIX standard, utimes() is a common alternative. If we
* have neither, there's no way to affect the mod or access time of
@@ -726,10 +743,10 @@ TouchSocketFile(void)
* In either path, we ignore errors; there's no point in complaining.
*/
#ifdef HAVE_UTIME
- utime(sock_path, NULL);
+ utime(cursocket, NULL);
#else /* !HAVE_UTIME */
#ifdef HAVE_UTIMES
- utimes(sock_path, NULL);
+ utimes(cursocket, NULL);
#endif /* HAVE_UTIMES */
#endif /* HAVE_UTIME */
}
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index eeea933..f91dcdd 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -156,7 +156,7 @@ static Backend *ShmemBackendArray;
/* The socket number we are listening for connections on */
int PostPortNumber;
-char *UnixSocketDir;
+char *UnixSocketDirs;
char *ListenAddresses;
/*
@@ -499,6 +499,10 @@ PostmasterMain(int argc, char *argv[])
char *userDoption = NULL;
bool listen_addr_saved = false;
int i;
+#ifdef HAVE_UNIX_SOCKETS
+ List *socketsList;
+ char *mainSocket = NULL;
+#endif
MyProcPid = PostmasterPid = getpid();
@@ -607,7 +611,7 @@ PostmasterMain(int argc, char *argv[])
break;
case 'k':
- SetConfigOption("unix_socket_directory", optarg, PGC_POSTMASTER, PGC_S_ARGV);
+ SetConfigOption("unix_socket_directories", optarg, PGC_POSTMASTER, PGC_S_ARGV);
break;
case 'l':
@@ -807,6 +811,40 @@ PostmasterMain(int argc, char *argv[])
}
/*
+ * We need to parse UnixSocketDirs here, because we want only
+ * the first socket directory be used in postmaster.pid, which is done
+ * in CreateDataDirLockFile().
+ */
+#ifdef HAVE_UNIX_SOCKETS
+ if (UnixSocketDirs)
+ {
+ char *rawSocketsString;
+ ListCell *l;
+
+ /* Need a modifiable copy of UnixSocketDirs */
+ rawSocketsString = pstrdup(UnixSocketDirs);
+
+ /* Parse string into list of directories */
+ if (!SplitDirectoriesString(rawSocketsString, ',', &socketsList))
+ {
+ /* syntax error in list */
+ ereport(FATAL,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid list syntax for \"unix_socket_directories\"")));
+ }
+
+ pfree(rawSocketsString);
+
+ if (l = list_head(socketsList))
+ mainSocket = (char *) lfirst(l);
+ else
+ mainSocket = UnixSocketDirs;
+ }
+ else
+ mainSocket = UnixSocketDirs;
+#endif
+
+ /*
* Create lockfile for data directory.
*
* We want to do this before we try to grab the input sockets, because the
@@ -815,7 +853,7 @@ PostmasterMain(int argc, char *argv[])
* For the same reason, it's best to grab the TCP socket(s) before the
* Unix socket.
*/
- CreateDataDirLockFile(true);
+ CreateDataDirLockFile(true, mainSocket);
/*
* Initialize SSL library, if specified.
@@ -862,12 +900,12 @@ PostmasterMain(int argc, char *argv[])
if (strcmp(curhost, "*") == 0)
status = StreamServerPort(AF_UNSPEC, NULL,
(unsigned short) PostPortNumber,
- UnixSocketDir,
+ UnixSocketDirs,
ListenSocket, MAXLISTEN);
else
status = StreamServerPort(AF_UNSPEC, curhost,
(unsigned short) PostPortNumber,
- UnixSocketDir,
+ UnixSocketDirs,
ListenSocket, MAXLISTEN);
if (status == STATUS_OK)
@@ -933,13 +971,89 @@ PostmasterMain(int argc, char *argv[])
#endif
#ifdef HAVE_UNIX_SOCKETS
- status = StreamServerPort(AF_UNIX, NULL,
- (unsigned short) PostPortNumber,
- UnixSocketDir,
- ListenSocket, MAXLISTEN);
- if (status != STATUS_OK)
- ereport(WARNING,
- (errmsg("could not create Unix-domain socket")));
+ /*
+ * We can specify several directories for Unix sockets to listen on,
+ * separated with ','. Socket name itself is the same in all cases.
+ */
+ if (!UnixSocketDirs)
+ {
+ status = StreamServerPort(AF_UNIX, NULL,
+ (unsigned short) PostPortNumber,
+ UnixSocketDirs,
+ ListenSocket, MAXLISTEN);
+ if (status != STATUS_OK)
+ ereport(WARNING,
+ (errmsg("could not create Unix-domain socket")));
+
+ }
+ else
+ {
+ ListCell *l;
+
+ /* We have parse string into list of directories earlier */
+ foreach(l, socketsList)
+ {
+ char *cursocket = (char *) lfirst(l);
+ char *colon;
+ char *port;
+ int64 portnum;
+ char *endptr;
+ bool bad_strtol;
+
+ /* syntax is directory or directory:port */
+ colon = strrchr(cursocket, ':');
+ if (colon != NULL)
+ {
+ port = colon + 1;
+ *colon = '\0';
+
+ /*
+ * convert port number to integer, ignoring optional trailing
+ * whitespace). strtol should ignore leading whitespace, too.
+ */
+ portnum = strtol(port, &endptr, 0);
+ bad_strtol = (errno == ERANGE);
+
+ while (isspace((unsigned char) *endptr))
+ endptr++;
+
+ if (*endptr != '\0')
+ ereport(FATAL,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("port number \"%s\" invalid in \"unix_socket_directories\"", port)));
+
+ if (bad_strtol || portnum < 1 || portnum > 65535)
+ ereport(FATAL,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("port number \"%s\" out of range in \"unix_socket_directories\"", port)));
+ }
+ else
+ {
+ portnum = PostPortNumber;
+ }
+
+ /* only absolute paths are allowed */
+ canonicalize_path(cursocket);
+ if (!is_absolute_path(cursocket))
+ {
+ ereport(FATAL,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("directory \"%s\" is not an absolute path", cursocket)));
+ }
+ else
+ {
+ status = StreamServerPort(AF_UNIX, NULL,
+ (unsigned short) portnum,
+ cursocket,
+ ListenSocket, MAXLISTEN);
+ if (status != STATUS_OK)
+ ereport(FATAL,
+ (errmsg("could not create secondary Unix-domain socket at \"%s\"", cursocket)));
+ }
+ }
+
+ list_free(socketsList);
+ }
#endif
/*
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 51b6df5..837d0e8 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -3343,7 +3343,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx)
break;
case 'k':
- SetConfigOption("unix_socket_directory", optarg, ctx, gucsource);
+ SetConfigOption("unix_socket_directories", optarg, ctx, gucsource);
break;
case 'l':
@@ -3660,7 +3660,7 @@ PostgresMain(int argc, char *argv[], const char *username)
/*
* Create lockfile for data directory.
*/
- CreateDataDirLockFile(false);
+ CreateDataDirLockFile(false, NULL);
}
/* Early initialization */
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index e1b57ba..ffc7e2b 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -2445,6 +2445,107 @@ SplitIdentifierString(char *rawstring, char separator,
return true;
}
+/*
+ * SplitDirectoriesString --- parse a string containing directories
+ *
+ * Inputs:
+ * rawstring: the input string; must be overwritable! On return, it's
+ * been modified to contain the separated directories.
+ * separator: the separator punctuation expected between directories
+ * (typically ',' or ';'). Whitespace may also appear around
+ * directories.
+ * Outputs:
+ * namelist: filled with a palloc'd list of pointers to directories within
+ * rawstring. Caller should list_free() this even on error return.
+ *
+ * Returns TRUE if okay, FALSE if there is a syntax error in the string.
+ *
+ * Note that an empty string is considered okay here.
+ */
+bool
+SplitDirectoriesString(char *rawstring, char separator,
+ List **namelist)
+{
+ char *nextp = rawstring;
+ bool done = false;
+
+ *namelist = NIL;
+
+ while (isspace((unsigned char) *nextp))
+ nextp++; /* skip leading whitespace */
+
+ if (*nextp == '\0')
+ return true; /* allow empty string */
+
+ /* At the top of the loop, we are at start of a new directories. */
+ do
+ {
+ char *curname;
+ char *endp;
+
+ if (*nextp == '\"')
+ {
+ /* Quoted name --- collapse quote-quote pairs */
+ curname = nextp + 1;
+ for (;;)
+ {
+ endp = strchr(nextp + 1, '\"');
+ if (endp == NULL)
+ return false; /* mismatched quotes */
+ if (endp[1] != '\"')
+ break; /* found end of quoted name */
+ /* Collapse adjacent quotes into one quote, and look again */
+ memmove(endp, endp + 1, strlen(endp));
+ nextp = endp;
+ }
+ /* endp now points at the terminating quote */
+ nextp = endp + 1;
+ }
+ else
+ {
+ /* Unquoted name --- extends to separator or whitespace */
+ curname = nextp;
+ while (*nextp && *nextp != separator &&
+ !isspace((unsigned char) *nextp))
+ nextp++;
+ endp = nextp;
+ if (curname == nextp)
+ return false; /* empty unquoted name not allowed */
+ }
+
+ while (isspace((unsigned char) *nextp))
+ nextp++; /* skip trailing whitespace */
+
+ if (*nextp == separator)
+ {
+ nextp++;
+ while (isspace((unsigned char) *nextp))
+ nextp++; /* skip leading whitespace for next */
+ /* we expect another name, so done remains false */
+ }
+ else if (*nextp == '\0')
+ done = true;
+ else
+ return false; /* invalid syntax */
+
+ /* Now safe to overwrite separator with a null */
+ *endp = '\0';
+
+ /* Truncate path if it's overlength */
+ if (strlen(curname) >= MAXPGPATH)
+ curname[MAXPGPATH-1] = '\0';
+
+ /*
+ * Finished isolating current name --- add it to list
+ */
+ *namelist = lappend(*namelist, pstrdup(curname));
+
+ /* Loop back if we didn't reach end of string */
+ } while (!done);
+
+ return true;
+}
+
/*****************************************************************************
* Comparison Functions used for bytea
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index fb376a0..704c33c 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -663,10 +663,11 @@ UnlinkLockFile(int status, Datum filename)
* filename is the name of the lockfile to create.
* amPostmaster is used to determine how to encode the output PID.
* isDDLock and refName are used to determine what error message to produce.
+ * socketPath is the path to the Unix socket we want to lock.
*/
static void
CreateLockFile(const char *filename, bool amPostmaster,
- bool isDDLock, const char *refName)
+ bool isDDLock, const char *refName, const char *socketPath)
{
int fd;
char buffer[MAXPGPATH * 2 + 256];
@@ -892,7 +893,8 @@ CreateLockFile(const char *filename, bool amPostmaster,
(long) MyStartTime,
PostPortNumber,
#ifdef HAVE_UNIX_SOCKETS
- (*UnixSocketDir != '\0') ? UnixSocketDir : DEFAULT_PGSOCKET_DIR
+ (socketPath && *socketPath != '\0') ? socketPath
+ : DEFAULT_PGSOCKET_DIR
#else
""
#endif
@@ -947,21 +949,22 @@ CreateLockFile(const char *filename, bool amPostmaster,
* helps ensure that we are locking the directory we should be.
*/
void
-CreateDataDirLockFile(bool amPostmaster)
+CreateDataDirLockFile(bool amPostmaster, const char *socketDir)
{
- CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, true, DataDir);
+ CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, true, DataDir, socketDir);
}
/*
* Create a lockfile for the specified Unix socket file.
*/
void
-CreateSocketLockFile(const char *socketfile, bool amPostmaster)
+CreateSocketLockFile(const char *socketfile, bool amPostmaster,
+ const char *socketDir)
{
char lockfile[MAXPGPATH];
snprintf(lockfile, sizeof(lockfile), "%s.lock", socketfile);
- CreateLockFile(lockfile, amPostmaster, false, socketfile);
+ CreateLockFile(lockfile, amPostmaster, false, socketfile, socketDir);
/* Save name of lockfile for TouchSocketLockFile */
strcpy(socketLockFile, lockfile);
}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index b756e58..bf90aff 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2894,14 +2894,15 @@ static struct config_string ConfigureNamesString[] =
},
{
- {"unix_socket_directory", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
- gettext_noop("Sets the directory where the Unix-domain socket will be created."),
- NULL,
+ {"unix_socket_directories", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
+ gettext_noop("Sets the directories where the Unix-domain socket will be created."),
+ gettext_noop("Directories are separated by \",\" and an additional "
+ "port number can be set, separated from directory by \":\"."),
GUC_SUPERUSER_ONLY
},
- &UnixSocketDir,
+ &UnixSocketDirs,
"",
- check_canonical_path, NULL, NULL
+ NULL, NULL, NULL
},
{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index fa75d00..b7f9ac9 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -65,7 +65,8 @@
# Note: Increasing max_connections costs ~400 bytes of shared memory per
# connection slot, plus lock space (see max_locks_per_transaction).
#superuser_reserved_connections = 3 # (change requires restart)
-#unix_socket_directory = '' # (change requires restart)
+#unix_socket_directories = '' # comma-separated list of directories
+ # (change requires restart)
#unix_socket_group = '' # (change requires restart)
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
# (change requires restart)
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index d7b8367..a407684 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -521,14 +521,27 @@ test_postmaster_connection(bool do_checkpoint)
hostaddr = optlines[LOCK_FILE_LINE_LISTEN_ADDR - 1];
/*
- * While unix_socket_directory can accept relative
+ * While unix_socket_directories can accept relative
* directories, libpq's host parameter must have a
* leading slash to indicate a socket directory. So,
* ignore sockdir if it's relative, and try to use TCP
* instead.
*/
if (sockdir[0] == '/')
- strlcpy(host_str, sockdir, sizeof(host_str));
+ {
+ char *rawstring;
+ char *comma;
+
+ /* Need a modifiable copy of UnixSocketDirs */
+ rawstring = xstrdup(sockdir);
+
+ /* We want only the first socket, in case more are defined */
+ if ((comma = strchr(rawstring, ',')) != NULL)
+ *comma = '\0';
+
+ strlcpy(host_str, rawstring, sizeof(host_str));
+ free(rawstring);
+ }
else
strlcpy(host_str, hostaddr, sizeof(host_str));
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index b186eed..40802cf 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -398,8 +398,9 @@ extern char *local_preload_libraries_string;
#define LOCK_FILE_LINE_LISTEN_ADDR 6
#define LOCK_FILE_LINE_SHMEM_KEY 7
-extern void CreateDataDirLockFile(bool amPostmaster);
-extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster);
+extern void CreateDataDirLockFile(bool amPostmaster, const char *socketDir);
+extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster,
+ const char *socketDir);
extern void TouchSocketLockFile(void);
extern void AddToDataDirLockFile(int target_line, const char *str);
extern void ValidatePgVersion(const char *path);
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 683ce3c..f19a3f8 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -19,7 +19,7 @@ extern int ReservedBackends;
extern int PostPortNumber;
extern int Unix_socket_permissions;
extern char *Unix_socket_group;
-extern char *UnixSocketDir;
+extern char *UnixSocketDirs;
extern char *ListenAddresses;
extern bool ClientAuthInProgress;
extern int PreAuthDelay;
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index d1e8370..65201fc 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -752,6 +752,8 @@ extern int varstr_cmp(char *arg1, int len1, char *arg2, int len2, Oid collid);
extern List *textToQualifiedNameList(text *textval);
extern bool SplitIdentifierString(char *rawstring, char separator,
List **namelist);
+extern bool SplitDirectoriesString(char *rawstring, char separator,
+ List **namelist);
extern Datum replace_text(PG_FUNCTION_ARGS);
extern text *replace_text_regexp(text *src_text, void *regexp,
text *replace_text, bool glob);
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers