*** doc/src/sgml/libpq.sgml 2 Dec 2009 14:07:25 -0000 1.292
--- doc/src/sgml/libpq.sgml 14 Jan 2010 17:02:59 -0000
***************
*** 5786,5791 **** myEventProc(PGEventId evtId, void *evtIn
--- 5786,5803 ----
+ PGSERVICEFILE
+
+ PGSERVICEFILE specifies the name of the per-user
+ connection service file. If not set, it defaults
+ to ~/.pg_service.conf>
+ (see ).
+
+
+
+
+
+
PGREALM
PGREALM sets the Kerberos realm to use with
***************
*** 5979,5985 **** myEventProc(PGEventId evtId, void *evtIn
PGSYSCONFDIR
PGSYSCONFDIR sets the directory containing the
! pg_service.conf> file.
--- 5991,5998 ----
PGSYSCONFDIR
PGSYSCONFDIR sets the directory containing the
! pg_service.conf> file and in a future version
! possibly other system-wide configuration files.
***************
*** 6055,6060 **** myEventProc(PGEventId evtId, void *evtIn
--- 6068,6076 ----
pg_service.conf
+
+ .pg_service.conf
+
The connection service file allows libpq connection parameters to be
***************
*** 6066,6077 **** myEventProc(PGEventId evtId, void *evtIn
! To use this feature, copy
! share/pg_service.conf.sample to
! etc/pg_service.conf and edit the file to add
! service names and parameters. This file can be used for client-only
! installs too. The file's location can also be specified by the
! PGSYSCONFDIR environment variable.
--- 6082,6111 ----
! The connection service file can be a per-user service file
! at ~/.pg_service.conf or the location
! specified by the environment variable PGSERVICEFILE,
! or it can be a system-wide file
! at etc/pg_service.conf or in the directory
! specified by the environment variable
! PGSYSCONFDIR. If service definitions with the same
! name exist in the user and the system file, the user file takes
! precedence.
!
!
!
! The file uses an INI file
format where the section
! name is the service name and the parameters are connection
! parameters. For example:
!
! # comment
! [mydb]
! host=somehost
! port=5433
! user=admin
!
! An example file is provided at
! share/pg_service.conf.sample.
*** src/interfaces/libpq/fe-connect.c 2 Jan 2010 16:58:11 -0000 1.382
--- src/interfaces/libpq/fe-connect.c 14 Jan 2010 17:02:59 -0000
***************
*** 269,274 **** static void defaultNoticeReceiver(void *
--- 269,279 ----
static void defaultNoticeProcessor(void *arg, const char *message);
static int parseServiceInfo(PQconninfoOption *options,
PQExpBuffer errorMessage);
+ static int parseServiceFile(const char *serviceFile,
+ const char *service,
+ PQconninfoOption *options,
+ PQExpBuffer errorMessage,
+ bool *group_found);
static char *pwdfMatchesString(char *buf, char *token);
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
char *username);
***************
*** 3088,3096 **** parseServiceInfo(PQconninfoOption *optio
{
char *service = conninfo_getval(options, "service");
char serviceFile[MAXPGPATH];
bool group_found = false;
! int linenr = 0,
! i;
/*
* We have to special-case the environment variable PGSERVICE here, since
--- 3093,3102 ----
{
char *service = conninfo_getval(options, "service");
char serviceFile[MAXPGPATH];
+ char *env;
bool group_found = false;
! int status;
! struct stat stat_buf;
/*
* We have to special-case the environment variable PGSERVICE here, since
***************
*** 3100,3253 **** parseServiceInfo(PQconninfoOption *optio
if (service == NULL)
service = getenv("PGSERVICE");
/*
* This could be used by any application so we can't use the binary
* location to find our config files.
*/
snprintf(serviceFile, MAXPGPATH, "%s/pg_service.conf",
getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR);
! if (service != NULL)
{
! FILE *f;
! char buf[MAXBUFSIZE],
! *line;
! f = fopen(serviceFile, "r");
! if (f == NULL)
{
! printfPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"),
serviceFile);
! return 1;
}
! while ((line = fgets(buf, sizeof(buf), f)) != NULL)
! {
! linenr++;
!
! if (strlen(line) >= sizeof(buf) - 1)
! {
! fclose(f);
! printfPQExpBuffer(errorMessage,
! libpq_gettext("line %d too long in service file \"%s\"\n"),
! linenr,
! serviceFile);
! return 2;
! }
! /* ignore EOL at end of line */
! if (strlen(line) && line[strlen(line) - 1] == '\n')
! line[strlen(line) - 1] = 0;
!
! /* ignore leading blanks */
! while (*line && isspace((unsigned char) line[0]))
! line++;
! /* ignore comments and empty lines */
! if (strlen(line) == 0 || line[0] == '#')
! continue;
! /* Check for right groupname */
! if (line[0] == '[')
{
! if (group_found)
! {
! /* group info already read */
! fclose(f);
! return 0;
! }
!
! if (strncmp(line + 1, service, strlen(service)) == 0 &&
! line[strlen(service) + 1] == ']')
! group_found = true;
! else
! group_found = false;
}
else
{
! if (group_found)
! {
! /*
! * Finally, we are in the right group and can parse the
! * line
! */
! char *key,
! *val;
! bool found_keyword;
#ifdef USE_LDAP
! if (strncmp(line, "ldap", 4) == 0)
! {
! int rc = ldapServiceLookup(line, options, errorMessage);
! /* if rc = 2, go on reading for fallback */
! switch (rc)
! {
! case 0:
! fclose(f);
! return 0;
! case 1:
! case 3:
! fclose(f);
! return 3;
! case 2:
! continue;
! }
}
#endif
! key = line;
! val = strchr(line, '=');
! if (val == NULL)
! {
! printfPQExpBuffer(errorMessage,
! libpq_gettext("syntax error in service file \"%s\", line %d\n"),
! serviceFile,
! linenr);
! fclose(f);
! return 3;
! }
! *val++ = '\0';
! /*
! * Set the parameter --- but don't override any previous
! * explicit setting.
! */
! found_keyword = false;
! for (i = 0; options[i].keyword; i++)
{
! if (strcmp(options[i].keyword, key) == 0)
! {
! if (options[i].val == NULL)
! options[i].val = strdup(val);
! found_keyword = true;
! break;
! }
}
! if (!found_keyword)
! {
! printfPQExpBuffer(errorMessage,
! libpq_gettext("syntax error in service file \"%s\", line %d\n"),
! serviceFile,
! linenr);
! fclose(f);
! return 3;
! }
}
}
}
-
- fclose(f);
-
- if (!group_found)
- {
- printfPQExpBuffer(errorMessage,
- libpq_gettext("definition of service \"%s\" not found\n"), service);
- return 3;
- }
}
return 0;
}
--- 3106,3301 ----
if (service == NULL)
service = getenv("PGSERVICE");
+ if (service == NULL)
+ return 0;
+
+ if ((env = getenv("PGSERVICEFILE")) != NULL)
+ strlcpy(serviceFile, env, sizeof(serviceFile));
+ else
+ {
+ char homedir[MAXPGPATH];
+
+ if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
+ {
+ printfPQExpBuffer(errorMessage, libpq_gettext("could not get home directory to locate service definition file"));
+ return 1;
+ }
+ snprintf(serviceFile, MAXPGPATH, "%s/%s", homedir, ".pg_service.conf");
+ errno = 0;
+ if (stat(serviceFile, &stat_buf) != 0 && errno == ENOENT)
+ goto next_file;
+ }
+
+ status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found);
+ if (group_found || status != 0)
+ return status;
+
+ next_file:
/*
* This could be used by any application so we can't use the binary
* location to find our config files.
*/
snprintf(serviceFile, MAXPGPATH, "%s/pg_service.conf",
getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR);
+ errno = 0;
+ if (stat(serviceFile, &stat_buf) != 0 && errno == ENOENT)
+ goto last_file;
! status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found);
! if (status != 0)
! return status;
!
! last_file:
! if (!group_found)
{
! printfPQExpBuffer(errorMessage,
! libpq_gettext("definition of service \"%s\" not found\n"), service);
! return 3;
! }
! return 0;
! }
!
! static int
! parseServiceFile(const char *serviceFile,
! const char *service,
! PQconninfoOption *options,
! PQExpBuffer errorMessage,
! bool *group_found)
! {
! int linenr = 0,
! i;
! FILE *f;
! char buf[MAXBUFSIZE],
! *line;
!
! f = fopen(serviceFile, "r");
! if (f == NULL)
! {
! printfPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"),
! serviceFile);
! return 1;
! }
!
! while ((line = fgets(buf, sizeof(buf), f)) != NULL)
! {
! linenr++;
!
! if (strlen(line) >= sizeof(buf) - 1)
{
! fclose(f);
! printfPQExpBuffer(errorMessage,
! libpq_gettext("line %d too long in service file \"%s\"\n"),
! linenr,
serviceFile);
! return 2;
}
! /* ignore EOL at end of line */
! if (strlen(line) && line[strlen(line) - 1] == '\n')
! line[strlen(line) - 1] = 0;
! /* ignore leading blanks */
! while (*line && isspace((unsigned char) line[0]))
! line++;
! /* ignore comments and empty lines */
! if (strlen(line) == 0 || line[0] == '#')
! continue;
! /* Check for right groupname */
! if (line[0] == '[')
! {
! if (*group_found)
{
! /* group info already read */
! fclose(f);
! return 0;
}
+
+ if (strncmp(line + 1, service, strlen(service)) == 0 &&
+ line[strlen(service) + 1] == ']')
+ *group_found = true;
else
+ *group_found = false;
+ }
+ else
+ {
+ if (*group_found)
{
! /*
! * Finally, we are in the right group and can parse
! * the line
! */
! char *key,
! *val;
! bool found_keyword;
#ifdef USE_LDAP
! if (strncmp(line, "ldap", 4) == 0)
! {
! int rc = ldapServiceLookup(line, options, errorMessage);
! /* if rc = 2, go on reading for fallback */
! switch (rc)
! {
! case 0:
! fclose(f);
! return 0;
! case 1:
! case 3:
! fclose(f);
! return 3;
! case 2:
! continue;
}
+ }
#endif
! key = line;
! val = strchr(line, '=');
! if (val == NULL)
! {
! printfPQExpBuffer(errorMessage,
! libpq_gettext("syntax error in service file \"%s\", line %d\n"),
! serviceFile,
! linenr);
! fclose(f);
! return 3;
! }
! *val++ = '\0';
! /*
! * Set the parameter --- but don't override any previous
! * explicit setting.
! */
! found_keyword = false;
! for (i = 0; options[i].keyword; i++)
! {
! if (strcmp(options[i].keyword, key) == 0)
{
! if (options[i].val == NULL)
! options[i].val = strdup(val);
! found_keyword = true;
! break;
}
+ }
! if (!found_keyword)
! {
! printfPQExpBuffer(errorMessage,
! libpq_gettext("syntax error in service file \"%s\", line %d\n"),
! serviceFile,
! linenr);
! fclose(f);
! return 3;
}
}
}
}
+ fclose(f);
+
return 0;
}