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 unix_socket_permissions (and possibly unix_socket_group) configuration parameters as described in . Or you - could set the unix_socket_directory + could set the unix_socket_directories configuration parameter to place the socket file in a suitably restricted directory. diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 074afee..d1727f8 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -453,17 +453,26 @@ SET ENABLE_SEQSCAN TO OFF; - - unix_socket_directory (string) + + unix_socket_directories (string) - unix_socket_directory configuration parameter + unix_socket_directories configuration parameter - 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 /tmp, but can be changed at build time. + Directories are separated by ',' and additional 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, + '/var/run, /tmp:5431' would create socket files + /var/run/.s.PGSQL.5432 and + /tmp/.s.PGSQL.5431. + It is not possible to define port number in the first + entry. If set, it will be ignored and default port + will be used. This parameter can only be set at server start. @@ -472,7 +481,7 @@ SET ENABLE_SEQSCAN TO OFF; .s.PGSQL.nnnn where nnnn is the server's port number, an ordinary file named .s.PGSQL.nnnn.lock will be - created in the unix_socket_directory directory. Neither + created in the unix_socket_directories directories. Neither file should ever be removed manually. @@ -6593,7 +6602,7 @@ LOG: CleanUpLock: deleting: lock(0xb7acd844) id(24688,24696,0,0,0,1) - unix_socket_directory = x + unix_socket_directories = x 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 The simplest way to prevent spoofing for local connections is to use a Unix domain 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 /tmp for the diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index e3ae92d..50d4167 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -31,6 +31,7 @@ #include "postmaster/bgwriter.h" #include "postmaster/startup.h" #include "postmaster/walwriter.h" +#include "postmaster/postmaster.h" #include "replication/walreceiver.h" #include "storage/bufmgr.h" #include "storage/ipc.h" @@ -349,7 +350,20 @@ AuxiliaryProcessMain(int argc, char *argv[]) /* If standalone, create lockfile for data directory */ if (!IsUnderPostmaster) - CreateDataDirLockFile(false); + { +#ifdef HAVE_UNIX_SOCKETS + List *socketsList; + char *mainSocket = NULL; +#endif + /* + * We need to parse UnixSocketDirs here, because we want the first + * socket directory, which will be used in postmaster.pid. + */ +#ifdef HAVE_UNIX_SOCKETS + SplitUnixDirectories(UnixSocketDirs, &socketsList, &mainSocket); +#endif + CreateDataDirLockFile(false, mainSocket); + } 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..0cc3521 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,15 @@ 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 + SplitUnixDirectories(UnixSocketDirs, &socketsList, &mainSocket); +#endif + + /* * Create lockfile for data directory. * * We want to do this before we try to grab the input sockets, because the @@ -815,7 +828,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 +875,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 +946,92 @@ 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; + bool first = TRUE; + + /* 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, except the first one */ + if ((colon = strrchr(cursocket, ':')) != 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))); + if (first) + portnum = PostPortNumber; + } + else + { + portnum = PostPortNumber; + } + first = FALSE; + + /* 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..22c8228 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': @@ -3647,6 +3647,10 @@ PostgresMain(int argc, char *argv[], const char *username) if (!IsUnderPostmaster) { +#ifdef HAVE_UNIX_SOCKETS + List *socketsList; + char *mainSocket = NULL; +#endif /* * Validate we have been given a reasonable-looking DataDir (if under * postmaster, assume postmaster did this already). @@ -3658,9 +3662,16 @@ PostgresMain(int argc, char *argv[], const char *username) ChangeToDataDir(); /* + * We need to parse UnixSocketDirs here, because we want the first + * socket directory, which will be used in postmaster.pid. + */ +#ifdef HAVE_UNIX_SOCKETS + SplitUnixDirectories(UnixSocketDirs, &socketsList, &mainSocket); +#endif + /* * Create lockfile for data directory. */ - CreateDataDirLockFile(false); + CreateDataDirLockFile(false, mainSocket); } /* Early initialization */ diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index e1b57ba..466d738 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -2445,6 +2445,155 @@ 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; +} + +/* + * parse UnixSocketDirs as a list of directory[:port], return the list + * in socketsList and store the first item into mainSocket. + */ +void +SplitUnixDirectories(char *unixSocketDirs, List **socketsList, + char **mainSocket) +{ +#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)) + { + char *colon; + + *mainSocket = (char *) lfirst(l); + + /* + * the first unix socket directory cannot contain :port + * and the default port is used every-time, so strip the port + */ + if ((colon = strrchr(*mainSocket, ':')) != NULL) + *colon = '\0'; + } + else + *mainSocket = unixSocketDirs; + } + else + *mainSocket = unixSocketDirs; +#endif +} /***************************************************************************** * Comparison Functions used for bytea diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index fb376a0..670e1a7 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); } @@ -1292,3 +1295,4 @@ pg_bindtextdomain(const char *domain) } #endif } + 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..1eea8aa 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -65,7 +65,9 @@ # 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:port, + # while the first socket's port is the default one + # (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 3826312..6d811ff 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -521,7 +521,7 @@ 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 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..492a08e 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -752,6 +752,10 @@ 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 void SplitUnixDirectories(char *unixSocketDirs, List **socketsList, + char **mainSocket); extern Datum replace_text(PG_FUNCTION_ARGS); extern text *replace_text_regexp(text *src_text, void *regexp, text *replace_text, bool glob);