diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 4e46451..5c00e2a 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -7421,6 +7421,9 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
.pg_service.conf
+
+ pg_service.conf.d
+
The connection service file allows libpq connection parameters to be
@@ -7444,6 +7447,17 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
+ Additional connection service files can be placed in the system-wide
+ directory `pg_config --sysconfdir`/pg_service.conf.d
+ or in the subdirectory pg_service.conf.d below the
+ directory specified by the environment variable
+ PGSYSCONFDIR. These will have the lowest precedence,
+ following the files described above. Files must end in '.conf' and
+ must not begin with '.'. Note if a single service is defined in
+ multiple files in this directory, which one gets used is not predictable.
+
+
+
The file uses an INI file
format where the section
name is the service name and the parameters are connection
parameters; see for a list. For
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 8d54333..9bd742f 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include "libpq-fe.h"
#include "libpq-int.h"
@@ -400,6 +401,10 @@ static void defaultNoticeReceiver(void *arg, const PGresult *res);
static void defaultNoticeProcessor(void *arg, const char *message);
static int parseServiceInfo(PQconninfoOption *options,
PQExpBuffer errorMessage);
+static int searchServiceFileDirectory(const char *service,
+ PQconninfoOption *options,
+ PQExpBuffer errorMessage,
+ bool *group_found);
static int parseServiceFile(const char *serviceFile,
const char *service,
PQconninfoOption *options,
@@ -4542,10 +4547,15 @@ next_file:
goto last_file;
status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found);
- if (status != 0)
+ if (group_found || status != 0)
return status;
last_file:
+
+ status = searchServiceFileDirectory(service, options, errorMessage, &group_found);
+ if (status != 0)
+ return status;
+
if (!group_found)
{
printfPQExpBuffer(errorMessage,
@@ -4556,6 +4566,64 @@ last_file:
return 0;
}
+/*
+ * searchServiceFileDirectory: Try to parse every file in pg_service.conf.d
+ * as a pg_service.conf style file.
+ *
+ * Returns 0 on success, nonzero on failure.
+ */
+static int
+searchServiceFileDirectory(const char *service,
+ PQconninfoOption *options,
+ PQExpBuffer errorMessage,
+ bool *group_found)
+{
+ char serviceDirPath[MAXPGPATH];
+ char serviceFile[MAXPGPATH];
+ int status;
+ int filenamelen;
+ struct stat stat_buf;
+ struct dirent *direntry;
+ DIR *serviceDir;
+
+ snprintf(serviceDirPath, MAXPGPATH, "%s/pg_service.conf.d",
+ getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR);
+
+ if (stat(serviceDirPath, &stat_buf) != 0 || !S_ISDIR(stat_buf.st_mode))
+ return 0;
+
+ serviceDir = opendir(serviceDirPath);
+ if (serviceDir == NULL)
+ return 0;
+
+ while ((direntry = readdir(serviceDir)) != NULL)
+ {
+ if (direntry->d_name[0] == '.')
+ continue;
+
+ filenamelen = strlen(direntry->d_name);
+ if (filenamelen < 6
+ || strcmp(direntry->d_name + filenamelen - 5, ".conf"))
+ continue;
+
+ snprintf(serviceFile, MAXPGPATH, "%s/%s", serviceDirPath,
+ direntry->d_name);
+
+ if (stat(serviceFile, &stat_buf) != 0 || !S_ISREG(stat_buf.st_mode)
+ || access(serviceFile, R_OK))
+ continue;
+
+ status = parseServiceFile(serviceFile, service, options, errorMessage,
+ group_found);
+ if (*group_found || status != 0)
+ break;
+ }
+
+ closedir(serviceDir);
+
+ return status;
+}
+
static int
parseServiceFile(const char *serviceFile,
const char *service,