diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 4e46451..ec4ba77 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,15 @@ 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. + + + 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..43ec0d5 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" @@ -4492,10 +4493,14 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage) { const char *service = conninfo_getval(options, "service"); char serviceFile[MAXPGPATH]; + char serviceDirPath[MAXPGPATH]; char *env; bool group_found = false; int status; struct stat stat_buf; + DIR *serviceDir; + struct dirent *direntry; + /* * We have to special-case the environment variable PGSERVICE here, since @@ -4539,21 +4544,45 @@ next_file: snprintf(serviceFile, MAXPGPATH, "%s/pg_service.conf", getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR); if (stat(serviceFile, &stat_buf) != 0) + goto conf_dir; + + status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found); + if (group_found || status != 0) + return status; + +conf_dir: + + /* + * Try every file in pg_service.conf.d/* + */ + 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) || + (serviceDir = opendir(serviceDirPath)) == NULL) goto last_file; - status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found); - if (status != 0) - return status; + while ((direntry = readdir(serviceDir)) != NULL) + { + 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) + { + closedir(serviceDir); + return status; + } + } + closedir(serviceDir); last_file: - if (!group_found) - { - printfPQExpBuffer(errorMessage, - libpq_gettext("definition of service \"%s\" not found\n"), service); - return 3; - } - - return 0; + printfPQExpBuffer(errorMessage, + libpq_gettext("definition of service \"%s\" not found\n"), service); + return 3; } static int