-<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.293 2010/01/20 00:42:28 rhaas Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.294 2010/01/20 21:15:21 petere Exp $ -->
<chapter id="libpq">
<title><application>libpq</application> - C Library</title>
</para>
</listitem>
+ <listitem>
+ <para>
+ <indexterm>
+ <primary><envar>PGSERVICEFILE</envar></primary>
+ </indexterm>
+ <envar>PGSERVICEFILE</envar> specifies the name of the per-user
+ connection service file. If not set, it defaults
+ to <filename>~/.pg_service.conf</>
+ (see <xref linkend="libpq-pgservice">).
+ </para>
+ </listitem>
+
<listitem>
<para>
<indexterm>
<primary><envar>PGSYSCONFDIR</envar></primary>
</indexterm>
<envar>PGSYSCONFDIR</envar> sets the directory containing the
- <filename>pg_service.conf</> file.
+ <filename>pg_service.conf</> file and in a future version
+ possibly other system-wide configuration files.
</para>
</listitem>
<indexterm zone="libpq-pgservice">
<primary>pg_service.conf</primary>
</indexterm>
+ <indexterm zone="libpq-pgservice">
+ <primary>.pg_service.conf</primary>
+ </indexterm>
<para>
The connection service file allows libpq connection parameters to be
</para>
<para>
- To use this feature, copy
- <filename>share/pg_service.conf.sample</filename> to
- <filename>etc/pg_service.conf</filename> 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
- <envar>PGSYSCONFDIR</envar> environment variable.
+ The connection service file can be a per-user service file
+ at <filename>~/.pg_service.conf</filename> or the location
+ specified by the environment variable <envar>PGSERVICEFILE</envar>,
+ or it can be a system-wide file
+ at <filename>etc/pg_service.conf</filename> or in the directory
+ specified by the environment variable
+ <envar>PGSYSCONFDIR</envar>. If service definitions with the same
+ name exist in the user and the system file, the user file takes
+ precedence.
+ </para>
+
+ <para>
+ The file uses an <quote>INI file</quote> format where the section
+ name is the service name and the parameters are connection
+ parameters; see <xref linkend="libpq-connect"> for a list. For
+ example:
+<programlisting>
+# comment
+[mydb]
+host=somehost
+port=5433
+user=admin
+</programlisting>
+ An example file is provided at
+ <filename>share/pg_service.conf.sample</filename>.
</para>
</sect1>
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.383 2010/01/15 09:19:10 heikki Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.384 2010/01/20 21:15:21 petere Exp $
*
*-------------------------------------------------------------------------
*/
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);
{
char *service = conninfo_getval(options, "service");
char serviceFile[MAXPGPATH];
+ char *env;
bool group_found = false;
- int linenr = 0,
- i;
+ int status;
+ struct stat stat_buf;
/*
* We have to special-case the environment variable PGSERVICE here, since
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;
+}
- if (service != NULL)
+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)
{
- FILE *f;
- char buf[MAXBUFSIZE],
- *line;
+ linenr++;
- f = fopen(serviceFile, "r");
- if (f == NULL)
+ if (strlen(line) >= sizeof(buf) - 1)
{
- printfPQExpBuffer(errorMessage, libpq_gettext("service file \"%s\" not found\n"),
+ fclose(f);
+ printfPQExpBuffer(errorMessage,
+ libpq_gettext("line %d too long in service file \"%s\"\n"),
+ linenr,
serviceFile);
- return 1;
+ return 2;
}
- 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 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 leading blanks */
- while (*line && isspace((unsigned char) line[0]))
- line++;
-
- /* ignore comments and empty lines */
- if (strlen(line) == 0 || line[0] == '#')
- continue;
+ /* ignore comments and empty lines */
+ if (strlen(line) == 0 || line[0] == '#')
+ continue;
- /* Check for right groupname */
- if (line[0] == '[')
+ /* Check for right groupname */
+ if (line[0] == '[')
+ {
+ if (*group_found)
{
- 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;
+ /* 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)
{
- if (group_found)
- {
- /*
- * Finally, we are in the right group and can parse the
- * line
- */
- char *key,
- *val;
- bool found_keyword;
+ /*
+ * 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 (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;
- }
+ /* 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';
+ 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++)
+ /*
+ * 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 (strcmp(options[i].keyword, key) == 0)
- {
- if (options[i].val == NULL)
- options[i].val = strdup(val);
- found_keyword = true;
- break;
- }
+ 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;
- }
+ 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;
- }
}
+ fclose(f);
+
return 0;
}