mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Support having multiple Unix-domain sockets per postmaster.
Replace unix_socket_directory with unix_socket_directories, which is a list of socket directories, and adjust postmaster's code to allow zero or more Unix-domain sockets to be created. This is mostly a straightforward change, but since the Unix sockets ought to be created after the TCP/IP sockets for safety reasons (better chance of detecting a port number conflict), AddToDataDirLockFile needs to be fixed to support out-of-order updates of data directory lockfile lines. That's a change that had been foreseen to be necessary someday anyway. Honza Horak, reviewed and revised by Tom Lane
This commit is contained in:
@ -838,7 +838,7 @@ omicron bryanh guest1
|
|||||||
<varname>unix_socket_permissions</varname> (and possibly
|
<varname>unix_socket_permissions</varname> (and possibly
|
||||||
<varname>unix_socket_group</varname>) configuration parameters as
|
<varname>unix_socket_group</varname>) configuration parameters as
|
||||||
described in <xref linkend="runtime-config-connection">. Or you
|
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
|
configuration parameter to place the socket file in a suitably
|
||||||
restricted directory.
|
restricted directory.
|
||||||
</para>
|
</para>
|
||||||
|
@ -445,17 +445,24 @@ SET ENABLE_SEQSCAN TO OFF;
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="guc-unix-socket-directory" xreflabel="unix_socket_directory">
|
<varlistentry id="guc-unix-socket-directories" xreflabel="unix_socket_directories">
|
||||||
<term><varname>unix_socket_directory</varname> (<type>string</type>)</term>
|
<term><varname>unix_socket_directories</varname> (<type>string</type>)</term>
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary><varname>unix_socket_directory</> configuration parameter</primary>
|
<primary><varname>unix_socket_directories</> configuration parameter</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Specifies the directory of the Unix-domain socket on which the
|
Specifies the directory of the Unix-domain socket(s) on which the
|
||||||
server is to listen for
|
server is to listen for connections from client applications.
|
||||||
connections from client applications. The default is normally
|
Multiple sockets can be created by listing multiple directories
|
||||||
<filename>/tmp</filename>, but can be changed at build time.
|
separated by commas. Whitespace between entries is
|
||||||
|
ignored; surround a directory name with double quotes if you need
|
||||||
|
to include whitespace or commas in the name.
|
||||||
|
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
|
||||||
|
<filename>/tmp</filename>, but that can be changed at build time.
|
||||||
This parameter can only be set at server start.
|
This parameter can only be set at server start.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@ -464,8 +471,8 @@ SET ENABLE_SEQSCAN TO OFF;
|
|||||||
<literal>.s.PGSQL.<replaceable>nnnn</></literal> where
|
<literal>.s.PGSQL.<replaceable>nnnn</></literal> where
|
||||||
<replaceable>nnnn</> is the server's port number, an ordinary file
|
<replaceable>nnnn</> is the server's port number, an ordinary file
|
||||||
named <literal>.s.PGSQL.<replaceable>nnnn</>.lock</literal> will be
|
named <literal>.s.PGSQL.<replaceable>nnnn</>.lock</literal> will be
|
||||||
created in the <varname>unix_socket_directory</> directory. Neither
|
created in each of the <varname>unix_socket_directories</> directories.
|
||||||
file should ever be removed manually.
|
Neither file should ever be removed manually.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -482,8 +489,8 @@ SET ENABLE_SEQSCAN TO OFF;
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Sets the owning group of the Unix-domain socket. (The owning
|
Sets the owning group of the Unix-domain socket(s). (The owning
|
||||||
user of the socket is always the user that starts the
|
user of the sockets is always the user that starts the
|
||||||
server.) In combination with the parameter
|
server.) In combination with the parameter
|
||||||
<varname>unix_socket_permissions</varname> this can be used as
|
<varname>unix_socket_permissions</varname> this can be used as
|
||||||
an additional access control mechanism for Unix-domain connections.
|
an additional access control mechanism for Unix-domain connections.
|
||||||
@ -506,7 +513,7 @@ SET ENABLE_SEQSCAN TO OFF;
|
|||||||
</indexterm>
|
</indexterm>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Sets the access permissions of the Unix-domain socket. Unix-domain
|
Sets the access permissions of the Unix-domain socket(s). Unix-domain
|
||||||
sockets use the usual Unix file system permission set.
|
sockets use the usual Unix file system permission set.
|
||||||
The parameter value is expected to be a numeric mode
|
The parameter value is expected to be a numeric mode
|
||||||
specified in the format accepted by the
|
specified in the format accepted by the
|
||||||
@ -1852,7 +1859,7 @@ SET ENABLE_SEQSCAN TO OFF;
|
|||||||
<varname>commit_delay</varname> behaved differently and was much
|
<varname>commit_delay</varname> behaved differently and was much
|
||||||
less effective: it affected only commits, rather than all WAL flushes,
|
less effective: it affected only commits, rather than all WAL flushes,
|
||||||
and waited for the entire configured delay even if the WAL flush
|
and waited for the entire configured delay even if the WAL flush
|
||||||
was completed sooner. Beginning in <productname>PostgreSQL</> 9.3,
|
was completed sooner. Beginning in <productname>PostgreSQL</> 9.3,
|
||||||
the first process that becomes ready to flush waits for the configured
|
the first process that becomes ready to flush waits for the configured
|
||||||
interval, while subsequent processes wait only until the leader
|
interval, while subsequent processes wait only until the leader
|
||||||
completes the flush. The default <varname>commit_delay</> is zero
|
completes the flush. The default <varname>commit_delay</> is zero
|
||||||
@ -6556,7 +6563,7 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1)
|
|||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry><option>-k <replaceable>x</replaceable></option></entry>
|
<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>
|
||||||
<row>
|
<row>
|
||||||
<entry><option>-l</option></entry>
|
<entry><option>-l</option></entry>
|
||||||
|
@ -254,8 +254,14 @@ PostgreSQL documentation
|
|||||||
<para>
|
<para>
|
||||||
Specifies the directory of the Unix-domain socket on which
|
Specifies the directory of the Unix-domain socket on which
|
||||||
<command>postgres</command> is to listen for
|
<command>postgres</command> is to listen for
|
||||||
connections from client applications. The default is normally
|
connections from client applications. The value can also be a
|
||||||
<filename>/tmp</filename>, but can be changed at build time.
|
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
|
||||||
|
<filename>/tmp</filename>, but that can be changed at build time.
|
||||||
|
Specifying this option is equivalent to setting the <xref
|
||||||
|
linkend="guc-unix-socket-directories"> configuration parameter.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
@ -1718,7 +1718,7 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
|
|||||||
<para>
|
<para>
|
||||||
The simplest way to prevent spoofing for <literal>local</>
|
The simplest way to prevent spoofing for <literal>local</>
|
||||||
connections is to use a Unix domain socket directory (<xref
|
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
|
for a trusted local user. This prevents a malicious user from creating
|
||||||
their own socket file in that directory. If you are concerned that
|
their own socket file in that directory. If you are concerned that
|
||||||
some applications might still reference <filename>/tmp</> for the
|
some applications might still reference <filename>/tmp</> for the
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
* StreamServerPort - Open postmaster's server port
|
* StreamServerPort - Open postmaster's server port
|
||||||
* StreamConnection - Create new connection with client
|
* StreamConnection - Create new connection with client
|
||||||
* StreamClose - Close a client/backend connection
|
* StreamClose - Close a client/backend connection
|
||||||
* TouchSocketFile - Protect socket file against /tmp cleaners
|
* TouchSocketFiles - Protect socket files against /tmp cleaners
|
||||||
* pq_init - initialize libpq at backend startup
|
* pq_init - initialize libpq at backend startup
|
||||||
* pq_comm_reset - reset libpq during error recovery
|
* pq_comm_reset - reset libpq during error recovery
|
||||||
* pq_close - shutdown libpq at backend exit
|
* pq_close - shutdown libpq at backend exit
|
||||||
@ -103,8 +103,8 @@ int Unix_socket_permissions;
|
|||||||
char *Unix_socket_group;
|
char *Unix_socket_group;
|
||||||
|
|
||||||
|
|
||||||
/* Where the Unix socket file is */
|
/* Where the Unix socket files are (list of palloc'd strings) */
|
||||||
static char sock_path[MAXPGPATH];
|
static List *sock_paths = NIL;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -140,8 +140,8 @@ static int internal_flush(void);
|
|||||||
static void pq_set_nonblocking(bool nonblocking);
|
static void pq_set_nonblocking(bool nonblocking);
|
||||||
|
|
||||||
#ifdef HAVE_UNIX_SOCKETS
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
static int Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName);
|
static int Lock_AF_UNIX(char *unixSocketDir, char *unixSocketPath);
|
||||||
static int Setup_AF_UNIX(void);
|
static int Setup_AF_UNIX(char *sock_path);
|
||||||
#endif /* HAVE_UNIX_SOCKETS */
|
#endif /* HAVE_UNIX_SOCKETS */
|
||||||
|
|
||||||
|
|
||||||
@ -234,29 +234,43 @@ pq_close(int code, Datum arg)
|
|||||||
|
|
||||||
/* StreamDoUnlink()
|
/* StreamDoUnlink()
|
||||||
* Shutdown routine for backend connection
|
* 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
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
static void
|
static void
|
||||||
StreamDoUnlink(int code, Datum arg)
|
StreamDoUnlink(int code, Datum arg)
|
||||||
{
|
{
|
||||||
Assert(sock_path[0]);
|
ListCell *l;
|
||||||
unlink(sock_path);
|
|
||||||
|
/* Loop through all created sockets... */
|
||||||
|
foreach(l, sock_paths)
|
||||||
|
{
|
||||||
|
char *sock_path = (char *) lfirst(l);
|
||||||
|
|
||||||
|
unlink(sock_path);
|
||||||
|
}
|
||||||
|
/* Since we're about to exit, no need to reclaim storage */
|
||||||
|
sock_paths = NIL;
|
||||||
}
|
}
|
||||||
#endif /* HAVE_UNIX_SOCKETS */
|
#endif /* HAVE_UNIX_SOCKETS */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* StreamServerPort -- open a "listening" port to accept connections.
|
* StreamServerPort -- open a "listening" port to accept connections.
|
||||||
*
|
*
|
||||||
* Successfully opened sockets are added to the ListenSocket[] array,
|
* family should be AF_UNIX or AF_UNSPEC; portNumber is the port number.
|
||||||
* at the first position that isn't PGINVALID_SOCKET.
|
* For AF_UNIX ports, hostName should be NULL and unixSocketDir must be
|
||||||
|
* specified. For TCP ports, hostName is either NULL for all interfaces or
|
||||||
|
* the interface to listen on, and unixSocketDir is ignored (can be NULL).
|
||||||
|
*
|
||||||
|
* Successfully opened sockets are added to the ListenSocket[] array (of
|
||||||
|
* length MaxListen), at the first position that isn't PGINVALID_SOCKET.
|
||||||
*
|
*
|
||||||
* RETURNS: STATUS_OK or STATUS_ERROR
|
* RETURNS: STATUS_OK or STATUS_ERROR
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||||
char *unixSocketName,
|
char *unixSocketDir,
|
||||||
pgsocket ListenSocket[], int MaxListen)
|
pgsocket ListenSocket[], int MaxListen)
|
||||||
{
|
{
|
||||||
pgsocket fd;
|
pgsocket fd;
|
||||||
@ -273,6 +287,9 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
int listen_index = 0;
|
int listen_index = 0;
|
||||||
int added = 0;
|
int added = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
|
char unixSocketPath[MAXPGPATH];
|
||||||
|
#endif
|
||||||
#if !defined(WIN32) || defined(IPV6_V6ONLY)
|
#if !defined(WIN32) || defined(IPV6_V6ONLY)
|
||||||
int one = 1;
|
int one = 1;
|
||||||
#endif
|
#endif
|
||||||
@ -286,10 +303,14 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
#ifdef HAVE_UNIX_SOCKETS
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
if (family == AF_UNIX)
|
if (family == AF_UNIX)
|
||||||
{
|
{
|
||||||
/* Lock_AF_UNIX will also fill in sock_path. */
|
/*
|
||||||
if (Lock_AF_UNIX(portNumber, unixSocketName) != STATUS_OK)
|
* Create unixSocketPath from portNumber and unixSocketDir and lock
|
||||||
|
* that file path
|
||||||
|
*/
|
||||||
|
UNIXSOCK_PATH(unixSocketPath, portNumber, unixSocketDir);
|
||||||
|
if (Lock_AF_UNIX(unixSocketDir, unixSocketPath) != STATUS_OK)
|
||||||
return STATUS_ERROR;
|
return STATUS_ERROR;
|
||||||
service = sock_path;
|
service = unixSocketPath;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif /* HAVE_UNIX_SOCKETS */
|
#endif /* HAVE_UNIX_SOCKETS */
|
||||||
@ -432,7 +453,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
(IS_AF_UNIX(addr->ai_family)) ?
|
(IS_AF_UNIX(addr->ai_family)) ?
|
||||||
errhint("Is another postmaster already running on port %d?"
|
errhint("Is another postmaster already running on port %d?"
|
||||||
" If not, remove socket file \"%s\" and retry.",
|
" If not, remove socket file \"%s\" and retry.",
|
||||||
(int) portNumber, sock_path) :
|
(int) portNumber, service) :
|
||||||
errhint("Is another postmaster already running on port %d?"
|
errhint("Is another postmaster already running on port %d?"
|
||||||
" If not, wait a few seconds and retry.",
|
" If not, wait a few seconds and retry.",
|
||||||
(int) portNumber)));
|
(int) portNumber)));
|
||||||
@ -443,7 +464,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
#ifdef HAVE_UNIX_SOCKETS
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
if (addr->ai_family == AF_UNIX)
|
if (addr->ai_family == AF_UNIX)
|
||||||
{
|
{
|
||||||
if (Setup_AF_UNIX() != STATUS_OK)
|
if (Setup_AF_UNIX(service) != STATUS_OK)
|
||||||
{
|
{
|
||||||
closesocket(fd);
|
closesocket(fd);
|
||||||
break;
|
break;
|
||||||
@ -490,10 +511,8 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
|||||||
* Lock_AF_UNIX -- configure unix socket file path
|
* Lock_AF_UNIX -- configure unix socket file path
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
|
Lock_AF_UNIX(char *unixSocketDir, char *unixSocketPath)
|
||||||
{
|
{
|
||||||
UNIXSOCK_PATH(sock_path, portNumber, unixSocketName);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grab an interlock file associated with the socket file.
|
* Grab an interlock file associated with the socket file.
|
||||||
*
|
*
|
||||||
@ -502,13 +521,23 @@ Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
|
|||||||
* more portable, and second, it lets us remove any pre-existing socket
|
* more portable, and second, it lets us remove any pre-existing socket
|
||||||
* file without race conditions.
|
* file without race conditions.
|
||||||
*/
|
*/
|
||||||
CreateSocketLockFile(sock_path, true);
|
CreateSocketLockFile(unixSocketPath, true, unixSocketDir);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Once we have the interlock, we can safely delete any pre-existing
|
* Once we have the interlock, we can safely delete any pre-existing
|
||||||
* socket file to avoid failure at bind() time.
|
* socket file to avoid failure at bind() time.
|
||||||
*/
|
*/
|
||||||
unlink(sock_path);
|
unlink(unixSocketPath);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Arrange to unlink the socket file(s) at proc_exit. If this is the
|
||||||
|
* first one, set up the on_proc_exit function to do it; then add this
|
||||||
|
* socket file to the list of files to unlink.
|
||||||
|
*/
|
||||||
|
if (sock_paths == NIL)
|
||||||
|
on_proc_exit(StreamDoUnlink, 0);
|
||||||
|
|
||||||
|
sock_paths = lappend(sock_paths, pstrdup(unixSocketPath));
|
||||||
|
|
||||||
return STATUS_OK;
|
return STATUS_OK;
|
||||||
}
|
}
|
||||||
@ -518,11 +547,8 @@ Lock_AF_UNIX(unsigned short portNumber, char *unixSocketName)
|
|||||||
* Setup_AF_UNIX -- configure unix socket permissions
|
* Setup_AF_UNIX -- configure unix socket permissions
|
||||||
*/
|
*/
|
||||||
static int
|
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);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix socket ownership/permission if requested. Note we must do this
|
* Fix socket ownership/permission if requested. Note we must do this
|
||||||
* before we listen() to avoid a window where unwanted connections could
|
* before we listen() to avoid a window where unwanted connections could
|
||||||
@ -704,20 +730,24 @@ StreamClose(pgsocket sock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TouchSocketFile -- mark socket file as recently accessed
|
* TouchSocketFiles -- mark socket files as recently accessed
|
||||||
*
|
*
|
||||||
* This routine should be called every so often to ensure that the socket
|
* 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
|
* files have a recent mod date (ordinary operations on sockets usually won't
|
||||||
* change the mod date). That saves it from being removed by
|
* change the mod date). That saves them from being removed by
|
||||||
* overenthusiastic /tmp-directory-cleaner daemons. (Another reason we should
|
* overenthusiastic /tmp-directory-cleaner daemons. (Another reason we should
|
||||||
* never have put the socket file in /tmp...)
|
* never have put the socket file in /tmp...)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
TouchSocketFile(void)
|
TouchSocketFiles(void)
|
||||||
{
|
{
|
||||||
/* Do nothing if we did not create a socket... */
|
ListCell *l;
|
||||||
if (sock_path[0] != '\0')
|
|
||||||
|
/* Loop through all created sockets... */
|
||||||
|
foreach(l, sock_paths)
|
||||||
{
|
{
|
||||||
|
char *sock_path = (char *) lfirst(l);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* utime() is POSIX standard, utimes() is a common alternative. If we
|
* 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
|
* have neither, there's no way to affect the mod or access time of
|
||||||
|
@ -157,7 +157,9 @@ static Backend *ShmemBackendArray;
|
|||||||
|
|
||||||
/* The socket number we are listening for connections on */
|
/* The socket number we are listening for connections on */
|
||||||
int PostPortNumber;
|
int PostPortNumber;
|
||||||
char *UnixSocketDir;
|
/* The directory names for Unix socket(s) */
|
||||||
|
char *Unix_socket_directories;
|
||||||
|
/* The TCP listen address(es) */
|
||||||
char *ListenAddresses;
|
char *ListenAddresses;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -612,7 +614,7 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'k':
|
case 'k':
|
||||||
SetConfigOption("unix_socket_directory", optarg, PGC_POSTMASTER, PGC_S_ARGV);
|
SetConfigOption("unix_socket_directories", optarg, PGC_POSTMASTER, PGC_S_ARGV);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
@ -856,7 +858,7 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
/* Need a modifiable copy of ListenAddresses */
|
/* Need a modifiable copy of ListenAddresses */
|
||||||
rawstring = pstrdup(ListenAddresses);
|
rawstring = pstrdup(ListenAddresses);
|
||||||
|
|
||||||
/* Parse string into list of identifiers */
|
/* Parse string into list of hostnames */
|
||||||
if (!SplitIdentifierString(rawstring, ',', &elemlist))
|
if (!SplitIdentifierString(rawstring, ',', &elemlist))
|
||||||
{
|
{
|
||||||
/* syntax error in list */
|
/* syntax error in list */
|
||||||
@ -872,12 +874,12 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
if (strcmp(curhost, "*") == 0)
|
if (strcmp(curhost, "*") == 0)
|
||||||
status = StreamServerPort(AF_UNSPEC, NULL,
|
status = StreamServerPort(AF_UNSPEC, NULL,
|
||||||
(unsigned short) PostPortNumber,
|
(unsigned short) PostPortNumber,
|
||||||
UnixSocketDir,
|
NULL,
|
||||||
ListenSocket, MAXLISTEN);
|
ListenSocket, MAXLISTEN);
|
||||||
else
|
else
|
||||||
status = StreamServerPort(AF_UNSPEC, curhost,
|
status = StreamServerPort(AF_UNSPEC, curhost,
|
||||||
(unsigned short) PostPortNumber,
|
(unsigned short) PostPortNumber,
|
||||||
UnixSocketDir,
|
NULL,
|
||||||
ListenSocket, MAXLISTEN);
|
ListenSocket, MAXLISTEN);
|
||||||
|
|
||||||
if (status == STATUS_OK)
|
if (status == STATUS_OK)
|
||||||
@ -896,7 +898,7 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
curhost)));
|
curhost)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success && list_length(elemlist))
|
if (!success && elemlist != NIL)
|
||||||
ereport(FATAL,
|
ereport(FATAL,
|
||||||
(errmsg("could not create any TCP/IP sockets")));
|
(errmsg("could not create any TCP/IP sockets")));
|
||||||
|
|
||||||
@ -943,13 +945,54 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_UNIX_SOCKETS
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
status = StreamServerPort(AF_UNIX, NULL,
|
if (Unix_socket_directories)
|
||||||
(unsigned short) PostPortNumber,
|
{
|
||||||
UnixSocketDir,
|
char *rawstring;
|
||||||
ListenSocket, MAXLISTEN);
|
List *elemlist;
|
||||||
if (status != STATUS_OK)
|
ListCell *l;
|
||||||
ereport(WARNING,
|
int success = 0;
|
||||||
(errmsg("could not create Unix-domain socket")));
|
|
||||||
|
/* Need a modifiable copy of Unix_socket_directories */
|
||||||
|
rawstring = pstrdup(Unix_socket_directories);
|
||||||
|
|
||||||
|
/* Parse string into list of directories */
|
||||||
|
if (!SplitDirectoriesString(rawstring, ',', &elemlist))
|
||||||
|
{
|
||||||
|
/* syntax error in list */
|
||||||
|
ereport(FATAL,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("invalid list syntax for \"unix_socket_directories\"")));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(l, elemlist)
|
||||||
|
{
|
||||||
|
char *socketdir = (char *) lfirst(l);
|
||||||
|
|
||||||
|
status = StreamServerPort(AF_UNIX, NULL,
|
||||||
|
(unsigned short) PostPortNumber,
|
||||||
|
socketdir,
|
||||||
|
ListenSocket, MAXLISTEN);
|
||||||
|
|
||||||
|
if (status == STATUS_OK)
|
||||||
|
{
|
||||||
|
success++;
|
||||||
|
/* record the first successful Unix socket in lockfile */
|
||||||
|
if (success == 1)
|
||||||
|
AddToDataDirLockFile(LOCK_FILE_LINE_SOCKET_DIR, socketdir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ereport(WARNING,
|
||||||
|
(errmsg("could not create Unix-domain socket in directory \"%s\"",
|
||||||
|
socketdir)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success && elemlist != NIL)
|
||||||
|
ereport(FATAL,
|
||||||
|
(errmsg("could not create any Unix-domain sockets")));
|
||||||
|
|
||||||
|
list_free_deep(elemlist);
|
||||||
|
pfree(rawstring);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1439,15 +1482,15 @@ ServerLoop(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Touch the socket and lock file every 58 minutes, to ensure that
|
* Touch Unix socket and lock files every 58 minutes, to ensure that
|
||||||
* they are not removed by overzealous /tmp-cleaning tasks. We assume
|
* they are not removed by overzealous /tmp-cleaning tasks. We assume
|
||||||
* no one runs cleaners with cutoff times of less than an hour ...
|
* no one runs cleaners with cutoff times of less than an hour ...
|
||||||
*/
|
*/
|
||||||
now = time(NULL);
|
now = time(NULL);
|
||||||
if (now - last_touch_time >= 58 * SECS_PER_MINUTE)
|
if (now - last_touch_time >= 58 * SECS_PER_MINUTE)
|
||||||
{
|
{
|
||||||
TouchSocketFile();
|
TouchSocketFiles();
|
||||||
TouchSocketLockFile();
|
TouchSocketLockFiles();
|
||||||
last_touch_time = now;
|
last_touch_time = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3344,7 +3344,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'k':
|
case 'k':
|
||||||
SetConfigOption("unix_socket_directory", optarg, ctx, gucsource);
|
SetConfigOption("unix_socket_directories", optarg, ctx, gucsource);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
@ -2446,6 +2446,116 @@ SplitIdentifierString(char *rawstring, char separator,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SplitDirectoriesString --- parse a string containing directory names
|
||||||
|
*
|
||||||
|
* This is similar to SplitIdentifierString, except that the parsing
|
||||||
|
* rules are meant to handle pathnames instead of identifiers: there is
|
||||||
|
* no downcasing, the max length is MAXPGPATH-1, and we apply
|
||||||
|
* canonicalize_path() to each extracted string. Because of the last,
|
||||||
|
* the returned strings are separately palloc'd rather than being
|
||||||
|
* pointers into rawstring --- but we still scribble on rawstring.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* rawstring: the input string; must be modifiable!
|
||||||
|
* separator: the separator punctuation expected between directories
|
||||||
|
* (typically ',' or ';'). Whitespace may also appear around
|
||||||
|
* directories.
|
||||||
|
* Outputs:
|
||||||
|
* namelist: filled with a palloc'd list of directory names.
|
||||||
|
* Caller should list_free_deep() 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 directory. */
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
curname = pstrdup(curname);
|
||||||
|
canonicalize_path(curname);
|
||||||
|
*namelist = lappend(*namelist, curname);
|
||||||
|
|
||||||
|
/* Loop back if we didn't reach end of string */
|
||||||
|
} while (!done);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Comparison Functions used for bytea
|
* Comparison Functions used for bytea
|
||||||
*
|
*
|
||||||
|
@ -49,8 +49,8 @@
|
|||||||
|
|
||||||
ProcessingMode Mode = InitProcessing;
|
ProcessingMode Mode = InitProcessing;
|
||||||
|
|
||||||
/* Note: we rely on this to initialize as zeroes */
|
/* List of lock files to be removed at proc exit */
|
||||||
static char socketLockFile[MAXPGPATH];
|
static List *lock_files = NIL;
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@ -628,7 +628,7 @@ GetUserNameFromId(Oid roleid)
|
|||||||
* Interlock-file support
|
* Interlock-file support
|
||||||
*
|
*
|
||||||
* These routines are used to create both a data-directory lockfile
|
* These routines are used to create both a data-directory lockfile
|
||||||
* ($DATADIR/postmaster.pid) and a Unix-socket-file lockfile ($SOCKFILE.lock).
|
* ($DATADIR/postmaster.pid) and Unix-socket-file lockfiles ($SOCKFILE.lock).
|
||||||
* Both kinds of files contain the same info initially, although we can add
|
* Both kinds of files contain the same info initially, although we can add
|
||||||
* more information to a data-directory lockfile after it's created, using
|
* more information to a data-directory lockfile after it's created, using
|
||||||
* AddToDataDirLockFile(). See miscadmin.h for documentation of the contents
|
* AddToDataDirLockFile(). See miscadmin.h for documentation of the contents
|
||||||
@ -640,32 +640,35 @@ GetUserNameFromId(Oid roleid)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* proc_exit callback to remove a lockfile.
|
* proc_exit callback to remove lockfiles.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
UnlinkLockFile(int status, Datum filename)
|
UnlinkLockFiles(int status, Datum arg)
|
||||||
{
|
{
|
||||||
char *fname = (char *) DatumGetPointer(filename);
|
ListCell *l;
|
||||||
|
|
||||||
if (fname != NULL)
|
foreach(l, lock_files)
|
||||||
{
|
{
|
||||||
if (unlink(fname) != 0)
|
char *curfile = (char *) lfirst(l);
|
||||||
{
|
|
||||||
/* Should we complain if the unlink fails? */
|
unlink(curfile);
|
||||||
}
|
/* Should we complain if the unlink fails? */
|
||||||
free(fname);
|
|
||||||
}
|
}
|
||||||
|
/* Since we're about to exit, no need to reclaim storage */
|
||||||
|
lock_files = NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a lockfile.
|
* Create a lockfile.
|
||||||
*
|
*
|
||||||
* filename is the name of the lockfile to create.
|
* filename is the path name of the lockfile to create.
|
||||||
* amPostmaster is used to determine how to encode the output PID.
|
* amPostmaster is used to determine how to encode the output PID.
|
||||||
|
* socketDir is the Unix socket directory path to include (possibly empty).
|
||||||
* isDDLock and refName are used to determine what error message to produce.
|
* isDDLock and refName are used to determine what error message to produce.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
CreateLockFile(const char *filename, bool amPostmaster,
|
CreateLockFile(const char *filename, bool amPostmaster,
|
||||||
|
const char *socketDir,
|
||||||
bool isDDLock, const char *refName)
|
bool isDDLock, const char *refName)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
@ -891,12 +894,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
|
|||||||
DataDir,
|
DataDir,
|
||||||
(long) MyStartTime,
|
(long) MyStartTime,
|
||||||
PostPortNumber,
|
PostPortNumber,
|
||||||
#ifdef HAVE_UNIX_SOCKETS
|
socketDir);
|
||||||
(*UnixSocketDir != '\0') ? UnixSocketDir : DEFAULT_PGSOCKET_DIR
|
|
||||||
#else
|
|
||||||
""
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
|
if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
|
||||||
@ -934,9 +932,14 @@ CreateLockFile(const char *filename, bool amPostmaster,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arrange for automatic removal of lockfile at proc_exit.
|
* Arrange to unlink the lock file(s) at proc_exit. If this is the
|
||||||
|
* first one, set up the on_proc_exit function to do it; then add this
|
||||||
|
* lock file to the list of files to unlink.
|
||||||
*/
|
*/
|
||||||
on_proc_exit(UnlinkLockFile, PointerGetDatum(strdup(filename)));
|
if (lock_files == NIL)
|
||||||
|
on_proc_exit(UnlinkLockFiles, 0);
|
||||||
|
|
||||||
|
lock_files = lappend(lock_files, pstrdup(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -945,41 +948,50 @@ CreateLockFile(const char *filename, bool amPostmaster,
|
|||||||
* When this is called, we must have already switched the working
|
* When this is called, we must have already switched the working
|
||||||
* directory to DataDir, so we can just use a relative path. This
|
* directory to DataDir, so we can just use a relative path. This
|
||||||
* helps ensure that we are locking the directory we should be.
|
* helps ensure that we are locking the directory we should be.
|
||||||
|
*
|
||||||
|
* Note that the socket directory path line is initially written as empty.
|
||||||
|
* postmaster.c will rewrite it upon creating the first Unix socket.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
CreateDataDirLockFile(bool amPostmaster)
|
CreateDataDirLockFile(bool amPostmaster)
|
||||||
{
|
{
|
||||||
CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, true, DataDir);
|
CreateLockFile(DIRECTORY_LOCK_FILE, amPostmaster, "", true, DataDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a lockfile for the specified Unix socket file.
|
* Create a lockfile for the specified Unix socket file.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
CreateSocketLockFile(const char *socketfile, bool amPostmaster)
|
CreateSocketLockFile(const char *socketfile, bool amPostmaster,
|
||||||
|
const char *socketDir)
|
||||||
{
|
{
|
||||||
char lockfile[MAXPGPATH];
|
char lockfile[MAXPGPATH];
|
||||||
|
|
||||||
snprintf(lockfile, sizeof(lockfile), "%s.lock", socketfile);
|
snprintf(lockfile, sizeof(lockfile), "%s.lock", socketfile);
|
||||||
CreateLockFile(lockfile, amPostmaster, false, socketfile);
|
CreateLockFile(lockfile, amPostmaster, socketDir, false, socketfile);
|
||||||
/* Save name of lockfile for TouchSocketLockFile */
|
|
||||||
strcpy(socketLockFile, lockfile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TouchSocketLockFile -- mark socket lock file as recently accessed
|
* TouchSocketLockFiles -- mark socket lock files as recently accessed
|
||||||
*
|
*
|
||||||
* This routine should be called every so often to ensure that the lock file
|
* This routine should be called every so often to ensure that the socket
|
||||||
* has a recent mod or access date. That saves it
|
* lock files have a recent mod or access date. That saves them
|
||||||
* from being removed by overenthusiastic /tmp-directory-cleaner daemons.
|
* from being removed by overenthusiastic /tmp-directory-cleaner daemons.
|
||||||
* (Another reason we should never have put the socket file in /tmp...)
|
* (Another reason we should never have put the socket file in /tmp...)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
TouchSocketLockFile(void)
|
TouchSocketLockFiles(void)
|
||||||
{
|
{
|
||||||
/* Do nothing if we did not create a socket... */
|
ListCell *l;
|
||||||
if (socketLockFile[0] != '\0')
|
|
||||||
|
foreach(l, lock_files)
|
||||||
{
|
{
|
||||||
|
char *socketLockFile = (char *) lfirst(l);
|
||||||
|
|
||||||
|
/* No need to touch the data directory lock file, we trust */
|
||||||
|
if (strcmp(socketLockFile, DIRECTORY_LOCK_FILE) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* utime() is POSIX standard, utimes() is a common alternative; if we
|
* utime() is POSIX standard, utimes() is a common alternative; if we
|
||||||
* have neither, fall back to actually reading the file (which only
|
* have neither, fall back to actually reading the file (which only
|
||||||
@ -1011,8 +1023,10 @@ TouchSocketLockFile(void)
|
|||||||
* Add (or replace) a line in the data directory lock file.
|
* Add (or replace) a line in the data directory lock file.
|
||||||
* The given string should not include a trailing newline.
|
* The given string should not include a trailing newline.
|
||||||
*
|
*
|
||||||
* Caution: this erases all following lines. In current usage that is OK
|
* Note: because we don't truncate the file, if we were to rewrite a line
|
||||||
* because lines are added in order. We could improve it if needed.
|
* with less data than it had before, there would be garbage after the last
|
||||||
|
* line. We don't ever actually do that, so not worth adding another kernel
|
||||||
|
* call to cover the possibility.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
AddToDataDirLockFile(int target_line, const char *str)
|
AddToDataDirLockFile(int target_line, const char *str)
|
||||||
@ -1020,8 +1034,10 @@ AddToDataDirLockFile(int target_line, const char *str)
|
|||||||
int fd;
|
int fd;
|
||||||
int len;
|
int len;
|
||||||
int lineno;
|
int lineno;
|
||||||
char *ptr;
|
char *srcptr;
|
||||||
char buffer[BLCKSZ];
|
char *destptr;
|
||||||
|
char srcbuffer[BLCKSZ];
|
||||||
|
char destbuffer[BLCKSZ];
|
||||||
|
|
||||||
fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0);
|
fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
@ -1032,7 +1048,7 @@ AddToDataDirLockFile(int target_line, const char *str)
|
|||||||
DIRECTORY_LOCK_FILE)));
|
DIRECTORY_LOCK_FILE)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
len = read(fd, buffer, sizeof(buffer) - 1);
|
len = read(fd, srcbuffer, sizeof(srcbuffer) - 1);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
{
|
{
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
@ -1042,36 +1058,50 @@ AddToDataDirLockFile(int target_line, const char *str)
|
|||||||
close(fd);
|
close(fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
buffer[len] = '\0';
|
srcbuffer[len] = '\0';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip over lines we are not supposed to rewrite.
|
* Advance over lines we are not supposed to rewrite, then copy them
|
||||||
|
* to destbuffer.
|
||||||
*/
|
*/
|
||||||
ptr = buffer;
|
srcptr = srcbuffer;
|
||||||
for (lineno = 1; lineno < target_line; lineno++)
|
for (lineno = 1; lineno < target_line; lineno++)
|
||||||
{
|
{
|
||||||
if ((ptr = strchr(ptr, '\n')) == NULL)
|
if ((srcptr = strchr(srcptr, '\n')) == NULL)
|
||||||
{
|
{
|
||||||
elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE);
|
elog(LOG, "bogus data in \"%s\"", DIRECTORY_LOCK_FILE);
|
||||||
close(fd);
|
close(fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ptr++;
|
srcptr++;
|
||||||
}
|
}
|
||||||
|
memcpy(destbuffer, srcbuffer, srcptr - srcbuffer);
|
||||||
|
destptr = destbuffer + (srcptr - srcbuffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write or rewrite the target line.
|
* Write or rewrite the target line.
|
||||||
*/
|
*/
|
||||||
snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s\n", str);
|
snprintf(destptr, destbuffer + sizeof(destbuffer) - destptr, "%s\n", str);
|
||||||
|
destptr += strlen(destptr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are more lines in the old file, append them to destbuffer.
|
||||||
|
*/
|
||||||
|
if ((srcptr = strchr(srcptr, '\n')) != NULL)
|
||||||
|
{
|
||||||
|
srcptr++;
|
||||||
|
snprintf(destptr, destbuffer + sizeof(destbuffer) - destptr, "%s",
|
||||||
|
srcptr);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And rewrite the data. Since we write in a single kernel call, this
|
* And rewrite the data. Since we write in a single kernel call, this
|
||||||
* update should appear atomic to onlookers.
|
* update should appear atomic to onlookers.
|
||||||
*/
|
*/
|
||||||
len = strlen(buffer);
|
len = strlen(destbuffer);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
if (lseek(fd, (off_t) 0, SEEK_SET) != 0 ||
|
if (lseek(fd, (off_t) 0, SEEK_SET) != 0 ||
|
||||||
(int) write(fd, buffer, len) != len)
|
(int) write(fd, destbuffer, len) != len)
|
||||||
{
|
{
|
||||||
/* if write didn't set errno, assume problem is no disk space */
|
/* if write didn't set errno, assume problem is no disk space */
|
||||||
if (errno == 0)
|
if (errno == 0)
|
||||||
|
@ -2895,14 +2895,18 @@ static struct config_string ConfigureNamesString[] =
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
{"unix_socket_directory", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
|
{"unix_socket_directories", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
|
||||||
gettext_noop("Sets the directory where the Unix-domain socket will be created."),
|
gettext_noop("Sets the directories where Unix-domain sockets will be created."),
|
||||||
NULL,
|
NULL,
|
||||||
GUC_SUPERUSER_ONLY
|
GUC_SUPERUSER_ONLY
|
||||||
},
|
},
|
||||||
&UnixSocketDir,
|
&Unix_socket_directories,
|
||||||
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
|
DEFAULT_PGSOCKET_DIR,
|
||||||
|
#else
|
||||||
"",
|
"",
|
||||||
check_canonical_path, NULL, NULL
|
#endif
|
||||||
|
NULL, NULL, NULL
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,8 @@
|
|||||||
# Note: Increasing max_connections costs ~400 bytes of shared memory per
|
# Note: Increasing max_connections costs ~400 bytes of shared memory per
|
||||||
# connection slot, plus lock space (see max_locks_per_transaction).
|
# connection slot, plus lock space (see max_locks_per_transaction).
|
||||||
#superuser_reserved_connections = 3 # (change requires restart)
|
#superuser_reserved_connections = 3 # (change requires restart)
|
||||||
#unix_socket_directory = '' # (change requires restart)
|
#unix_socket_directories = '/tmp' # comma-separated list of directories
|
||||||
|
# (change requires restart)
|
||||||
#unix_socket_group = '' # (change requires restart)
|
#unix_socket_group = '' # (change requires restart)
|
||||||
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
|
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
|
||||||
# (change requires restart)
|
# (change requires restart)
|
||||||
|
@ -1156,7 +1156,7 @@ static void
|
|||||||
setup_config(void)
|
setup_config(void)
|
||||||
{
|
{
|
||||||
char **conflines;
|
char **conflines;
|
||||||
char repltok[TZ_STRLEN_MAX + 100];
|
char repltok[MAXPGPATH];
|
||||||
char path[MAXPGPATH];
|
char path[MAXPGPATH];
|
||||||
const char *default_timezone;
|
const char *default_timezone;
|
||||||
|
|
||||||
@ -1178,6 +1178,15 @@ setup_config(void)
|
|||||||
n_buffers * (BLCKSZ / 1024));
|
n_buffers * (BLCKSZ / 1024));
|
||||||
conflines = replace_token(conflines, "#shared_buffers = 32MB", repltok);
|
conflines = replace_token(conflines, "#shared_buffers = 32MB", repltok);
|
||||||
|
|
||||||
|
#ifdef HAVE_UNIX_SOCKETS
|
||||||
|
snprintf(repltok, sizeof(repltok), "#unix_socket_directories = '%s'",
|
||||||
|
DEFAULT_PGSOCKET_DIR);
|
||||||
|
#else
|
||||||
|
snprintf(repltok, sizeof(repltok), "#unix_socket_directories = ''");
|
||||||
|
#endif
|
||||||
|
conflines = replace_token(conflines, "#unix_socket_directories = '/tmp'",
|
||||||
|
repltok);
|
||||||
|
|
||||||
#if DEF_PGPORT != 5432
|
#if DEF_PGPORT != 5432
|
||||||
snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT);
|
snprintf(repltok, sizeof(repltok), "#port = %d", DEF_PGPORT);
|
||||||
conflines = replace_token(conflines, "#port = 5432", repltok);
|
conflines = replace_token(conflines, "#port = 5432", repltok);
|
||||||
|
@ -521,7 +521,7 @@ test_postmaster_connection(bool do_checkpoint)
|
|||||||
hostaddr = optlines[LOCK_FILE_LINE_LISTEN_ADDR - 1];
|
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
|
* directories, libpq's host parameter must have a
|
||||||
* leading slash to indicate a socket directory. So,
|
* leading slash to indicate a socket directory. So,
|
||||||
* ignore sockdir if it's relative, and try to use TCP
|
* ignore sockdir if it's relative, and try to use TCP
|
||||||
|
@ -44,12 +44,12 @@ typedef struct
|
|||||||
/*
|
/*
|
||||||
* prototypes for functions in pqcomm.c
|
* prototypes for functions in pqcomm.c
|
||||||
*/
|
*/
|
||||||
extern int StreamServerPort(int family, char *hostName,
|
extern int StreamServerPort(int family, char *hostName,
|
||||||
unsigned short portNumber, char *unixSocketName, pgsocket ListenSocket[],
|
unsigned short portNumber, char *unixSocketDir,
|
||||||
int MaxListen);
|
pgsocket ListenSocket[], int MaxListen);
|
||||||
extern int StreamConnection(pgsocket server_fd, Port *port);
|
extern int StreamConnection(pgsocket server_fd, Port *port);
|
||||||
extern void StreamClose(pgsocket sock);
|
extern void StreamClose(pgsocket sock);
|
||||||
extern void TouchSocketFile(void);
|
extern void TouchSocketFiles(void);
|
||||||
extern void pq_init(void);
|
extern void pq_init(void);
|
||||||
extern void pq_comm_reset(void);
|
extern void pq_comm_reset(void);
|
||||||
extern int pq_getbytes(char *s, size_t len);
|
extern int pq_getbytes(char *s, size_t len);
|
||||||
|
@ -411,7 +411,7 @@ extern char *local_preload_libraries_string;
|
|||||||
* 2 data directory path
|
* 2 data directory path
|
||||||
* 3 postmaster start timestamp (time_t representation)
|
* 3 postmaster start timestamp (time_t representation)
|
||||||
* 4 port number
|
* 4 port number
|
||||||
* 5 socket directory path (empty on Windows)
|
* 5 first Unix socket directory path (empty if none)
|
||||||
* 6 first listen_address (IP address or "*"; empty if no TCP port)
|
* 6 first listen_address (IP address or "*"; empty if no TCP port)
|
||||||
* 7 shared memory key (not present on Windows)
|
* 7 shared memory key (not present on Windows)
|
||||||
*
|
*
|
||||||
@ -429,8 +429,9 @@ extern char *local_preload_libraries_string;
|
|||||||
#define LOCK_FILE_LINE_SHMEM_KEY 7
|
#define LOCK_FILE_LINE_SHMEM_KEY 7
|
||||||
|
|
||||||
extern void CreateDataDirLockFile(bool amPostmaster);
|
extern void CreateDataDirLockFile(bool amPostmaster);
|
||||||
extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster);
|
extern void CreateSocketLockFile(const char *socketfile, bool amPostmaster,
|
||||||
extern void TouchSocketLockFile(void);
|
const char *socketDir);
|
||||||
|
extern void TouchSocketLockFiles(void);
|
||||||
extern void AddToDataDirLockFile(int target_line, const char *str);
|
extern void AddToDataDirLockFile(int target_line, const char *str);
|
||||||
extern void ValidatePgVersion(const char *path);
|
extern void ValidatePgVersion(const char *path);
|
||||||
extern void process_shared_preload_libraries(void);
|
extern void process_shared_preload_libraries(void);
|
||||||
|
@ -19,7 +19,7 @@ extern int ReservedBackends;
|
|||||||
extern int PostPortNumber;
|
extern int PostPortNumber;
|
||||||
extern int Unix_socket_permissions;
|
extern int Unix_socket_permissions;
|
||||||
extern char *Unix_socket_group;
|
extern char *Unix_socket_group;
|
||||||
extern char *UnixSocketDir;
|
extern char *Unix_socket_directories;
|
||||||
extern char *ListenAddresses;
|
extern char *ListenAddresses;
|
||||||
extern bool ClientAuthInProgress;
|
extern bool ClientAuthInProgress;
|
||||||
extern int PreAuthDelay;
|
extern int PreAuthDelay;
|
||||||
|
@ -756,6 +756,8 @@ extern int varstr_cmp(char *arg1, int len1, char *arg2, int len2, Oid collid);
|
|||||||
extern List *textToQualifiedNameList(text *textval);
|
extern List *textToQualifiedNameList(text *textval);
|
||||||
extern bool SplitIdentifierString(char *rawstring, char separator,
|
extern bool SplitIdentifierString(char *rawstring, char separator,
|
||||||
List **namelist);
|
List **namelist);
|
||||||
|
extern bool SplitDirectoriesString(char *rawstring, char separator,
|
||||||
|
List **namelist);
|
||||||
extern Datum replace_text(PG_FUNCTION_ARGS);
|
extern Datum replace_text(PG_FUNCTION_ARGS);
|
||||||
extern text *replace_text_regexp(text *src_text, void *regexp,
|
extern text *replace_text_regexp(text *src_text, void *regexp,
|
||||||
text *replace_text, bool glob);
|
text *replace_text, bool glob);
|
||||||
|
Reference in New Issue
Block a user