v3-0001-Add-support-for-abstract-Unix-domain-sockets.patch
text/plain
Filename: v3-0001-Add-support-for-abstract-Unix-domain-sockets.patch
Type: text/plain
Part: 0
Message:
Re: abstract Unix-domain sockets
Patch
Format: format-patch
Series: patch v3-0001
Subject: Add support for abstract Unix-domain sockets
| File | + | − |
|---|---|---|
| doc/src/sgml/config.sgml | 23 | 1 |
| doc/src/sgml/libpq.sgml | 4 | 1 |
| src/backend/libpq/pqcomm.c | 8 | 0 |
| src/bin/psql/command.c | 5 | 10 |
| src/bin/psql/prompt.c | 2 | 1 |
| src/common/ip.c | 23 | 1 |
| src/include/libpq/pqcomm.h | 9 | 0 |
| src/interfaces/libpq/fe-connect.c | 2 | 2 |
From a4967dd79e490390bc148d3bae92452ba4a34c9c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 22 Oct 2020 08:47:52 +0200
Subject: [PATCH v3 1/2] Add support for abstract Unix-domain sockets
This is a variant of the normal Unix-domain sockets that don't use the
file system but a separate "abstract" namespace. At the user
interface, such sockets are represented by names starting with "@".
Supported on Linux and Windows right now.
Discussion: https://www.postgresql.org/message-id/flat/6dee8574-b0ad-fc49-9c8c-2edc796f0033@2ndquadrant.com
---
doc/src/sgml/config.sgml | 24 +++++++++++++++++++++++-
doc/src/sgml/libpq.sgml | 5 ++++-
src/backend/libpq/pqcomm.c | 8 ++++++++
src/bin/psql/command.c | 15 +++++----------
src/bin/psql/prompt.c | 3 ++-
src/common/ip.c | 24 +++++++++++++++++++++++-
src/include/libpq/pqcomm.h | 9 +++++++++
src/interfaces/libpq/fe-connect.c | 4 ++--
8 files changed, 76 insertions(+), 16 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index a632cf98ba..d05045fb20 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -749,6 +749,21 @@ <title>Connection Settings</title>
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.
+ </para>
+
+ <para>
+ A value that starts with <literal>@</literal> specifies that a
+ Unix-domain socket in the abstract namespace should be created
+ (currently supported on Linux and Windows). In that case, this value
+ does not specify a <quote>directory</quote> but a prefix from which
+ the actual socket name is computed in the same manner as for the
+ file-system namespace. While the abstract socket name prefix can be
+ chosen freely, since it is not a file-system location, the convention
+ is to nonetheless use file-system-like values such as
+ <literal>@/tmp</literal>.
+ </para>
+
+ <para>
The default value is normally
<filename>/tmp</filename>, but that can be changed at build time.
On Windows, the default is empty, which means no Unix-domain socket is
@@ -763,6 +778,7 @@ <title>Connection Settings</title>
named <literal>.s.PGSQL.<replaceable>nnnn</replaceable>.lock</literal> will be
created in each of the <varname>unix_socket_directories</varname> directories.
Neither file should ever be removed manually.
+ For sockets in the abstract namespace, no lock file is created.
</para>
</listitem>
</varlistentry>
@@ -787,7 +803,8 @@ <title>Connection Settings</title>
<para>
This parameter is not supported on Windows. Any setting will be
- ignored.
+ ignored. Also, sockets in the abstract namespace have no file owner,
+ so this setting is also ignored in that case.
</para>
</listitem>
</varlistentry>
@@ -834,6 +851,11 @@ <title>Connection Settings</title>
similar effect by pointing <varname>unix_socket_directories</varname> to a
directory having search permission limited to the desired audience.
</para>
+
+ <para>
+ Sockets in the abstract namespace have no file permissions, so this
+ setting is also ignored in that case.
+ </para>
</listitem>
</varlistentry>
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 9d4b6ab4a8..06bd412044 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1031,7 +1031,10 @@ <title>Parameter Key Words</title>
communication; the value is the name of the directory in which the
socket file is stored. (On Unix, an absolute path name begins with a
slash. On Windows, paths starting with drive letters are also
- recognized.) The default behavior when <literal>host</literal> is not
+ recognized.) If the host name starts with <literal>@</literal>, it is
+ taken as a Unix-domain socket in the abstract namespace (currently
+ supported on Linux and Windows).
+ The default behavior when <literal>host</literal> is not
specified, or is empty, is to connect to a Unix-domain
socket<indexterm><primary>Unix domain socket</primary></indexterm> in
<filename>/tmp</filename> (or whatever socket directory was specified
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index ac986c0505..84568508c5 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -611,6 +611,10 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
static int
Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath)
{
+ /* no lock file for abstract sockets */
+ if (unixSocketPath[0] == '@')
+ return STATUS_OK;
+
/*
* Grab an interlock file associated with the socket file.
*
@@ -642,6 +646,10 @@ Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath)
static int
Setup_AF_UNIX(const char *sock_path)
{
+ /* no file system permissions for abstract sockets */
+ if (sock_path[0] == '@')
+ return STATUS_OK;
+
/*
* Fix socket ownership/permission if requested. Note we must do this
* before we listen() to avoid a window where unwanted connections could
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index c7a83d5dfc..55b349d55a 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -37,6 +37,7 @@
#include "input.h"
#include "large_obj.h"
#include "libpq-fe.h"
+#include "libpq/pqcomm.h"
#include "mainloop.h"
#include "portability/instr_time.h"
#include "pqexpbuffer.h"
@@ -604,12 +605,9 @@ exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
char *host = PQhost(pset.db);
char *hostaddr = PQhostaddr(pset.db);
- /*
- * If the host is an absolute path, the connection is via socket
- * unless overridden by hostaddr
- */
- if (is_absolute_path(host))
+ if (is_unixsock_path(host))
{
+ /* hostaddr overrides host */
if (hostaddr && *hostaddr)
printf(_("You are connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
db, PQuser(pset.db), hostaddr, PQport(pset.db));
@@ -3407,12 +3405,9 @@ do_connect(enum trivalue reuse_previous_specification,
char *host = PQhost(pset.db);
char *hostaddr = PQhostaddr(pset.db);
- /*
- * If the host is an absolute path, the connection is via socket
- * unless overridden by hostaddr
- */
- if (is_absolute_path(host))
+ if (is_unixsock_path(host))
{
+ /* hostaddr overrides host */
if (hostaddr && *hostaddr)
printf(_("You are now connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
PQdb(pset.db), PQuser(pset.db), hostaddr, PQport(pset.db));
diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c
index ef503ec41b..f42c3dfc74 100644
--- a/src/bin/psql/prompt.c
+++ b/src/bin/psql/prompt.c
@@ -15,6 +15,7 @@
#include "common.h"
#include "common/string.h"
#include "input.h"
+#include "libpq/pqcomm.h"
#include "prompt.h"
#include "settings.h"
@@ -136,7 +137,7 @@ get_prompt(promptStatus_t status, ConditionalStack cstack)
const char *host = PQhost(pset.db);
/* INET socket */
- if (host && host[0] && !is_absolute_path(host))
+ if (host && host[0] && !is_unixsock_path(host))
{
strlcpy(buf, host, sizeof(buf));
if (*p == 'm')
diff --git a/src/common/ip.c b/src/common/ip.c
index 69fcca8479..bcc779e00c 100644
--- a/src/common/ip.c
+++ b/src/common/ip.c
@@ -217,6 +217,21 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
strcpy(unp->sun_path, path);
+ /*
+ * If the supplied path starts with @, replace that with a zero byte for
+ * the internal representation. In that mode, the entire sun_path is the
+ * address, including trailing zero bytes. But we set the address length
+ * to only include the length of the original string. That way the
+ * trailing zero bytes won't show up in any network or socket lists of the
+ * operating system. This is just a convention, also followed by other
+ * packages.
+ */
+ if (path[0] == '@')
+ {
+ unp->sun_path[0] = '\0';
+ aip->ai_addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(path);
+ }
+
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
unp->sun_len = sizeof(struct sockaddr_un);
#endif
@@ -249,7 +264,14 @@ getnameinfo_unix(const struct sockaddr_un *sa, int salen,
if (service)
{
- ret = snprintf(service, servicelen, "%s", sa->sun_path);
+ /*
+ * Check whether it looks like an abstract socket, but it could also
+ * just be an empty string.
+ */
+ if (sa->sun_path[0] == '\0' && sa->sun_path[1] != '\0')
+ ret = snprintf(service, servicelen, "@%s", sa->sun_path + 1);
+ else
+ ret = snprintf(service, servicelen, "%s", sa->sun_path);
if (ret < 0 || ret >= servicelen)
return EAI_MEMORY;
}
diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h
index 781d86c8ef..cf967c3987 100644
--- a/src/include/libpq/pqcomm.h
+++ b/src/include/libpq/pqcomm.h
@@ -85,6 +85,15 @@ typedef struct
*/
#define UNIXSOCK_PATH_BUFLEN sizeof(((struct sockaddr_un *) NULL)->sun_path)
+/*
+ * A host that looks either like an absolute path or starts with @ is
+ * interpreted as a Unix-domain socket address.
+ */
+static inline bool
+is_unixsock_path(const char *path)
+{
+ return is_absolute_path(path) || path[0] == '@';
+}
/*
* These manipulate the frontend/backend protocol version number.
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index e7781d010f..7d04d3664e 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1093,7 +1093,7 @@ connectOptions2(PGconn *conn)
{
ch->type = CHT_HOST_NAME;
#ifdef HAVE_UNIX_SOCKETS
- if (is_absolute_path(ch->host))
+ if (is_unixsock_path(ch->host))
ch->type = CHT_UNIX_SOCKET;
#endif
}
@@ -6945,7 +6945,7 @@ passwordFromFile(const char *hostname, const char *port, const char *dbname,
/* 'localhost' matches pghost of '' or the default socket directory */
if (hostname == NULL || hostname[0] == '\0')
hostname = DefaultHost;
- else if (is_absolute_path(hostname))
+ else if (is_unixsock_path(hostname))
/*
* We should probably use canonicalize_path(), but then we have to
base-commit: 16f96c74d48e65da23d28665103e2c4c9d3414cc
--
2.29.2