]> granicus.if.org Git - postgresql/commitdiff
Add user-specific .pg_service.conf file
authorPeter Eisentraut <peter_e@gmx.net>
Wed, 20 Jan 2010 21:15:21 +0000 (21:15 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Wed, 20 Jan 2010 21:15:21 +0000 (21:15 +0000)
This extends the existing pg_service.conf facility to first look for a
service definition file in the user's home directory.

doc/src/sgml/libpq.sgml
src/interfaces/libpq/fe-connect.c

index cfa87d0adaec3f77c13e2fbd1085ff75cf9d5540..a5386cf333d92470583a1bd655cfc3c918c232d5 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $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>
@@ -5791,6 +5791,18 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
      </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>
@@ -5987,7 +5999,8 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
        <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>
 
@@ -6063,6 +6076,9 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
   <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
@@ -6074,12 +6090,31 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
   </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>
 
index 125d93cf0b1eb0f6cadd40de101f728191cf6932..4d7be078c0725994ef240cb98b14f3ce02b49665 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -272,6 +272,11 @@ 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 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);
@@ -3095,9 +3100,10 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
 {
        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
@@ -3107,154 +3113,196 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
        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;
 }