Re: [HACKERS] Configuration patch - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: [HACKERS] Configuration patch
Date
Msg-id 200407110016.i6B0Gut02848@candle.pha.pa.us
Whole thread Raw
In response to Re: [HACKERS] Configuration patch  (pgsql@mohawksoft.com)
List pgsql-patches
I have applied the non-"include" parts of this patch, which allows the
configuration files to exist outside the data directory. I have added a
TODO:

    * Add include functionality to postgresql.conf

Patch attached and applied.  It still needs more documentation.  Right
now only the postmaster manual page describes this functionality.  Maybe
it needs initdb support too so it can be done automatically.  Is this a
TODO?

Also, the old code allowed the postmaster to start if it couldn't find
postgresql.conf.  I changed it in this patch because the new decoupling
of the file locations makes a missing postgresql.conf much more likely,
and of course it will never work without a postgresql.conf when they are
decoupled anyway.  Should we fail if we can't find pg_ident.conf?  Right
now we don't.

---------------------------------------------------------------------------

pgsql@mohawksoft.com wrote:
> > pgsql@mohawksoft.com writes:
> >>> AFAICS this patch breaks standalone backends, since the smarts involved
> >>> in dealing with the new flavors of directory layouts were not taught to
> >>> postgres.c.
> >
> >> Hmm, I guess its time to get a CVS version of PG. This was originally
> >> done
> >> in 7.3 and migrated to 7.4. 7.5 is substantially different?
> >
> > The same issue applied in 7.4 and before; but yes, all that code looks
> > noticeably different in CVS tip.
> >
> >> As for include not being a variable, no it isn't. It is a new class of
> >> GUC
> >> parameter. Would you like a better syntax?
> >
> > As I said, I think this "class of GUC parameter" is ill-considered.
>
> See below
> >
> >> FWIW: This is exactly the same syntax that was discussed, and no one
> >> brought up that it was a problem. You even said you liked the idea of
> >> "include."
> >
> > I like the idea of include.  I don't like this implementation.
>
> OK.
>
> >
> >> I wanted to create a generic facility for "smarter" configuration. Being
> >> able to create functions and pass parameters should allow smaller more
> >> focused configuration parsing.
> >
> > I don't believe "include" is a representative of a class; it seems a
> > specialized one-of-a-kind thing.  If you had one or two more examples
> > of this class then I might think you are onto something, but as-is
> > there is no reason to think that you've got a well-defined idea or
> > have made the right decisions about how it should work.
>
> OK, imagine this, maybe not right now, but in the future......
>
> In the configuration file, one can load C code modules like in apache. Not
> just SQL functions, but modules of functionality, like foreign table
> types.
> >
> > Basically, include is not a variable because neither "set include" nor
> > "show include" are sensible operations at all.  Implementing it in a way
> > that makes you have to deal with these possibilities is simply
> > wrongheaded.
> >
> > Another reason why it's not a variable is that processing it as a
> > variable means the sub-file is not read in the order that the user would
> > naturally expect; with the implementation as you have it, the behavior
> > would be quite surprising as to which file wins if both outer file and
> > subfile set the same variable.  (Take another look at guc-file.l: it
> > eats the whole file and only then starts to evaluate variables.)
> >
> > What I'd think is reasonable is a special case hack in guc-file.l that
> > checks for opt_name = "include" and does something immediately upon
> > seeing it.  (CVS tip has a special hack for "custom_variable_classes"
> > here, which has got problems of its own because that *is* a variable,
> > but that's right around where I'd envision inserting code for include.)
> >
> >> I'm open to suggestions. Would you prefer stating the function
> >> parameters
> >> with a special character? '#' is taken, how about '!' ? is in:
> >
> > It's not the syntax I'm objecting to; it's the implementation.
> >
> >             regards, tom lane
> >
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
>
>                http://archives.postgresql.org
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: doc/src/sgml/runtime.sgml
===================================================================
RCS file: /cvsroot/pgsql-server/doc/src/sgml/runtime.sgml,v
retrieving revision 1.268
diff -c -c -r1.268 runtime.sgml
*** doc/src/sgml/runtime.sgml    27 Jun 2004 22:58:19 -0000    1.268
--- doc/src/sgml/runtime.sgml    11 Jul 2004 00:06:48 -0000
***************
*** 563,568 ****
--- 563,616 ----
      any desired selection condition.
     </para>

+    <sect2 id="runtime-config-configuration-files">
+     <title>Configuration Files</title>
+
+      <variablelist>
+
+      <varlistentry id="guc-pgdata" xreflabel="pgdata">
+       <term><varname>pgdata</varname> (<type>string</type>)</term>
+       <listitem>
+        <para>
+          Specifies the directory to use for data storage (everything except
+          configuration files).
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-hba-conf" xreflabel="hba-conf">
+       <term><varname>hba_conf</varname> (<type>string</type>)</term>
+       <listitem>
+        <para>
+          Specifies the file name to use for configuration of host-based
+          authentication (HBA).
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-ident-conf" xreflabel="ident-conf">
+       <term><varname>ident_conf</varname> (<type>string</type>)</term>
+       <listitem>
+        <para>
+          Specifies the file name to use for configuration of
+          <application>ident</> authentication.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="external-pidfile" xreflabel="external-pidfile">
+       <term><varname>external_pidfile</varname> (<type>string</type>)</term>
+       <listitem>
+        <para>
+          Specifies the location of an additional <application>postmaster</>
+          process-id (PID) file for use by server administration programs.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      </variablelist>
+    </sect2>
+
     <sect2 id="runtime-config-connection">
      <title>Connections and Authentication</title>

Index: doc/src/sgml/ref/postmaster.sgml
===================================================================
RCS file: /cvsroot/pgsql-server/doc/src/sgml/ref/postmaster.sgml,v
retrieving revision 1.50
diff -c -c -r1.50 postmaster.sgml
*** doc/src/sgml/ref/postmaster.sgml    21 Jun 2004 04:06:04 -0000    1.50
--- doc/src/sgml/ref/postmaster.sgml    11 Jul 2004 00:06:49 -0000
***************
*** 67,80 ****
     One <command>postmaster</command> always manages the data
     from exactly one database cluster.  A database cluster is a
     collection of databases that is stored at a common file system
!    location.  When the <command>postmaster</command> starts it needs to know the location
!    of the database cluster files (<quote>data area</quote>).  This is
!    done with the <option>-D</option> invocation option or the
!    <envar>PGDATA</envar> environment variable; there is no default.
!    More than one <command>postmaster</command> process can run on a system at one time,
!    as long as they use different data areas and different
     communication ports (see below).  A data area is created with <xref
     linkend="app-initdb">.
    </para>
   </refsect1>

--- 67,93 ----
     One <command>postmaster</command> always manages the data
     from exactly one database cluster.  A database cluster is a
     collection of databases that is stored at a common file system
!    location.  When the <command>postmaster</command> starts it needs
!    to know the location of the database cluster files (<quote>data
!    area</quote>).
!    More than one <command>postmaster</command> process can run on a system
!    at one time as long as they use different data areas and different
     communication ports (see below).  A data area is created with <xref
     linkend="app-initdb">.
+   </para>
+
+   <para>
+    The <quote>data area</> is specified by the <option>-D</option> option
+    or the <envar>PGDATA</envar> environment variable; there is no default.
+    Typically, it points to a directory created by <application>
+    initdb</>.  However, for administrative flexibility, you can
+    point to a directory containing only configuration files:
+    <filename>postgresql.conf</>, <filename>pg_hba.conf</>, and
+    <filename>pg_ident.conf</>. You can then set
+    <filename>postgresql.conf</>'s <varname>pgdata</> to point to the
+    data directory. You can also point just to the server configuration file
+    like <filename>postgresql.conf</> and set its variables to point to the
+    other configuration files and the data directory.
    </para>
   </refsect1>

Index: src/backend/bootstrap/bootstrap.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/bootstrap/bootstrap.c,v
retrieving revision 1.185
diff -c -c -r1.185 bootstrap.c
*** src/backend/bootstrap/bootstrap.c    24 Jun 2004 21:02:24 -0000    1.185
--- src/backend/bootstrap/bootstrap.c    11 Jul 2004 00:06:50 -0000
***************
*** 212,218 ****
      char       *dbname;
      int            flag;
      int            xlogop = BS_XLOG_NOP;
!     char       *potential_DataDir = NULL;

      /*
       * initialize globals
--- 212,218 ----
      char       *dbname;
      int            flag;
      int            xlogop = BS_XLOG_NOP;
!     char       *userPGDATA = NULL;

      /*
       * initialize globals
***************
*** 236,243 ****
      if (!IsUnderPostmaster)
      {
          InitializeGUCOptions();
!         potential_DataDir = getenv("PGDATA");    /* Null if no PGDATA
!                                                  * variable */
      }

      /* Ignore the initial -boot argument, if present */
--- 236,242 ----
      if (!IsUnderPostmaster)
      {
          InitializeGUCOptions();
!         userPGDATA = getenv("PGDATA");    /* Null if no PGDATA variable */
      }

      /* Ignore the initial -boot argument, if present */
***************
*** 252,258 ****
          switch (flag)
          {
              case 'D':
!                 potential_DataDir = optarg;
                  break;
              case 'd':
                  {
--- 251,257 ----
          switch (flag)
          {
              case 'D':
!                 userPGDATA = optarg;
                  break;
              case 'd':
                  {
***************
*** 326,332 ****

      if (!IsUnderPostmaster)
      {
!         if (!potential_DataDir)
          {
              write_stderr("%s does not know where to find the database system data.\n"
                           "You must specify the directory that contains the database system\n"
--- 325,331 ----

      if (!IsUnderPostmaster)
      {
!         if (!userPGDATA)
          {
              write_stderr("%s does not know where to find the database system data.\n"
                           "You must specify the directory that contains the database system\n"
***************
*** 335,341 ****
                           argv[0]);
              proc_exit(1);
          }
!         SetDataDir(potential_DataDir);
      }

      /* Validate we have been given a reasonable-looking DataDir */
--- 334,340 ----
                           argv[0]);
              proc_exit(1);
          }
!         SetDataDir(userPGDATA);
      }

      /* Validate we have been given a reasonable-looking DataDir */
Index: src/backend/libpq/hba.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/libpq/hba.c,v
retrieving revision 1.125
diff -c -c -r1.125 hba.c
*** src/backend/libpq/hba.c    30 May 2004 23:40:26 -0000    1.125
--- src/backend/libpq/hba.c    11 Jul 2004 00:06:52 -0000
***************
*** 35,40 ****
--- 35,41 ----
  #include "miscadmin.h"
  #include "nodes/pg_list.h"
  #include "storage/fd.h"
+ #include "utils/guc.h"


  /* Max size of username ident server can return */
***************
*** 1029,1045 ****
  void
  load_hba(void)
  {
-     int            bufsize;
      FILE       *file;            /* The config file we have to read */
      char       *conf_file;        /* The name of the config file */

      if (hba_lines || hba_line_nums)
          free_lines(&hba_lines, &hba_line_nums);

!     /* Put together the full pathname to the config file. */
!     bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char);
!     conf_file = (char *) palloc(bufsize);
!     snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE);

      file = AllocateFile(conf_file, "r");
      if (file == NULL)
--- 1030,1051 ----
  void
  load_hba(void)
  {
      FILE       *file;            /* The config file we have to read */
      char       *conf_file;        /* The name of the config file */

      if (hba_lines || hba_line_nums)
          free_lines(&hba_lines, &hba_line_nums);

!     /* HBA filename in config file */
!     if (guc_hbafile)
!         conf_file = pstrdup(guc_hbafile);
!     else
!     {
!         char *confloc = (user_pgconfig_is_dir) ? user_pgconfig : DataDir;
!         /* put together the full pathname to the config file */
!         conf_file = palloc(strlen(confloc) + strlen(CONF_FILE) + 2);
!         sprintf(conf_file, "%s/%s", confloc, CONF_FILE);
!     }

      file = AllocateFile(conf_file, "r");
      if (file == NULL)
***************
*** 1178,1193 ****
      FILE       *file;            /* The map file we have to read */
      char       *map_file;        /* The name of the map file we have to
                                   * read */
-     int            bufsize;
-
      if (ident_lines || ident_line_nums)
          free_lines(&ident_lines, &ident_line_nums);

!     /* put together the full pathname to the map file */
!     bufsize = (strlen(DataDir) + strlen(USERMAP_FILE) + 2) * sizeof(char);
!     map_file = (char *) palloc(bufsize);
!     snprintf(map_file, bufsize, "%s/%s", DataDir, USERMAP_FILE);
!
      file = AllocateFile(map_file, "r");
      if (file == NULL)
      {
--- 1184,1203 ----
      FILE       *file;            /* The map file we have to read */
      char       *map_file;        /* The name of the map file we have to
                                   * read */
      if (ident_lines || ident_line_nums)
          free_lines(&ident_lines, &ident_line_nums);

!     /* IDENT filename in config file */
!     if (guc_identfile)
!         map_file = pstrdup(guc_identfile);
!     else
!     {
!         /* put together the full pathname to the map file */
!         char *confloc = (user_pgconfig_is_dir) ? user_pgconfig : DataDir;
!         map_file = (char *) palloc(strlen(confloc) + strlen(USERMAP_FILE) + 2);
!         sprintf(map_file, "%s/%s", confloc, USERMAP_FILE);
!     }
!
      file = AllocateFile(map_file, "r");
      if (file == NULL)
      {
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v
retrieving revision 1.405
diff -c -c -r1.405 postmaster.c
*** src/backend/postmaster/postmaster.c    24 Jun 2004 21:02:55 -0000    1.405
--- src/backend/postmaster/postmaster.c    11 Jul 2004 00:06:57 -0000
***************
*** 233,238 ****
--- 233,239 ----
   * postmaster.c - function prototypes
   */
  static void checkDataDir(const char *checkdir);
+ static bool onlyConfigSpecified(const char *checkdir);
  #ifdef USE_RENDEZVOUS
  static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode,
                        void *context);
***************
*** 306,312 ****
  {
      int            opt;
      int            status;
!     char       *potential_DataDir = NULL;
      int            i;

      progname = get_progname(argv[0]);
--- 307,313 ----
  {
      int            opt;
      int            status;
!     char       *userPGDATA = NULL;
      int            i;

      progname = get_progname(argv[0]);
***************
*** 370,376 ****
       */
      InitializeGUCOptions();

!     potential_DataDir = getenv("PGDATA");        /* default value */

      opterr = 1;

--- 371,377 ----
       */
      InitializeGUCOptions();

!     userPGDATA = getenv("PGDATA");        /* default value */

      opterr = 1;

***************
*** 395,401 ****
                  /* Can no longer set the backend executable file to use. */
                  break;
              case 'D':
!                 potential_DataDir = optarg;
                  break;
              case 'd':
                  {
--- 396,402 ----
                  /* Can no longer set the backend executable file to use. */
                  break;
              case 'D':
!                 userPGDATA = optarg;
                  break;
              case 'd':
                  {
***************
*** 523,535 ****
          ExitPostmaster(1);
      }

!     /*
!      * Now we can set the data directory, and then read postgresql.conf.
!      */
!     checkDataDir(potential_DataDir);    /* issues error messages */
!     SetDataDir(potential_DataDir);

!     ProcessConfigFile(PGC_POSTMASTER);

      /* If timezone is not set, determine what the OS uses */
      pg_timezone_initialize();
--- 524,572 ----
          ExitPostmaster(1);
      }

!     if (onlyConfigSpecified(userPGDATA))
!     {
!         /*
!          *    It is either a file name or a directory with no
!          *    global/pg_control file, and hence not a data directory.
!          */
!         user_pgconfig = userPGDATA;
!         ProcessConfigFile(PGC_POSTMASTER);
!
!         if (!guc_pgdata)    /* Got a pgdata from the config file? */
!         {
!             write_stderr("%s does not know where to find the database system data.\n"
!                          "This should be specified as 'pgdata' in %s%s.\n",
!                          progname, userPGDATA,
!                          user_pgconfig_is_dir ? "/postgresql.conf" : "");
!             ExitPostmaster(2);
!         }
!         checkDataDir(guc_pgdata);
!         SetDataDir(guc_pgdata);
!     }
!     else
!     {
!         /* Now we can set the data directory, and then read postgresql.conf. */
!         checkDataDir(userPGDATA);
!         SetDataDir(userPGDATA);
!         ProcessConfigFile(PGC_POSTMASTER);
!     }

!     if (external_pidfile)
!     {
!         FILE *fpidfile = fopen(external_pidfile, "w");
!
!         if (fpidfile)
!         {
!             fprintf(fpidfile, "%d\n", MyProcPid);
!             fclose(fpidfile);
!             /* Should we remove the pid file on postmaster exit? */
!         }
!         else
!             fprintf(stderr,
!                 gettext("%s could not write to external pid file %s\n"),
!                 progname, external_pidfile);
!     }

      /* If timezone is not set, determine what the OS uses */
      pg_timezone_initialize();
***************
*** 847,852 ****
--- 884,915 ----
  }


+
+ static bool
+ onlyConfigSpecified(const char *checkdir)
+ {
+     char    path[MAXPGPATH];
+     struct stat stat_buf;
+
+     if (checkdir == NULL)            /* checkDataDir handles this */
+         return FALSE;
+
+     if (stat(checkdir, &stat_buf) == -1)    /* ditto */
+         return FALSE;
+
+     if (S_ISREG(stat_buf.st_mode))        /* It's a regular file, so assume it's explict */
+         return TRUE;
+     else if (S_ISDIR(stat_buf.st_mode))    /* It's a directory, is it a config or system dir? */
+     {
+         snprintf(path, MAXPGPATH, "%s/global/pg_control", checkdir);
+         /* If this is not found, it is a config-only directory */
+         if (stat(path, &stat_buf) == -1)
+             return TRUE;
+     }
+     return FALSE;
+ }
+
+
  /*
   * Validate the proposed data directory
   */
***************
*** 861,868 ****
      {
          write_stderr("%s does not know where to find the database system data.\n"
                       "You must specify the directory that contains the database system\n"
!                      "either by specifying the -D invocation option or by setting the\n"
!                      "PGDATA environment variable.\n",
                       progname);
          ExitPostmaster(2);
      }
--- 924,931 ----
      {
          write_stderr("%s does not know where to find the database system data.\n"
                       "You must specify the directory that contains the database system\n"
!                      "or configuration files by either specifying the -D invocation option\n"
!                      "or by setting the PGDATA environment variable.\n",
                       progname);
          ExitPostmaster(2);
      }
***************
*** 872,883 ****
          if (errno == ENOENT)
              ereport(FATAL,
                      (errcode_for_file_access(),
!                      errmsg("data directory \"%s\" does not exist",
                              checkdir)));
          else
              ereport(FATAL,
                      (errcode_for_file_access(),
!              errmsg("could not read permissions of directory \"%s\": %m",
                      checkdir)));
      }

--- 935,946 ----
          if (errno == ENOENT)
              ereport(FATAL,
                      (errcode_for_file_access(),
!                      errmsg("data or configuration location \"%s\" does not exist",
                              checkdir)));
          else
              ereport(FATAL,
                      (errcode_for_file_access(),
!              errmsg("could not read permissions of \"%s\": %m",
                      checkdir)));
      }

Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/tcop/postgres.c,v
retrieving revision 1.422
diff -c -c -r1.422 postgres.c
*** src/backend/tcop/postgres.c    1 Jul 2004 00:51:11 -0000    1.422
--- src/backend/tcop/postgres.c    11 Jul 2004 00:07:04 -0000
***************
*** 2164,2170 ****
  {
      int            flag;
      const char *dbname = NULL;
!     char       *potential_DataDir = NULL;
      bool        secure;
      int            errs = 0;
      int            debug_flag = 0;
--- 2164,2170 ----
  {
      int            flag;
      const char *dbname = NULL;
!     char       *userPGDATA = NULL;
      bool        secure;
      int            errs = 0;
      int            debug_flag = 0;
***************
*** 2235,2241 ****
      if (!IsUnderPostmaster)
      {
          InitializeGUCOptions();
!         potential_DataDir = getenv("PGDATA");
      }

      /* ----------------
--- 2235,2241 ----
      if (!IsUnderPostmaster)
      {
          InitializeGUCOptions();
!         userPGDATA = getenv("PGDATA");
      }

      /* ----------------
***************
*** 2283,2289 ****

              case 'D':            /* PGDATA directory */
                  if (secure)
!                     potential_DataDir = optarg;
                  break;

              case 'd':            /* debug level */
--- 2283,2289 ----

              case 'D':            /* PGDATA directory */
                  if (secure)
!                     userPGDATA = optarg;
                  break;

              case 'd':            /* debug level */
***************
*** 2574,2585 ****
           * set up handler to log session end.
           */
          if (IsUnderPostmaster && Log_disconnections)
!             on_proc_exit(log_disconnections,0);
      }

      if (!IsUnderPostmaster)
      {
!         if (!potential_DataDir)
          {
              write_stderr("%s does not know where to find the database system data.\n"
                           "You must specify the directory that contains the database system\n"
--- 2574,2585 ----
           * set up handler to log session end.
           */
          if (IsUnderPostmaster && Log_disconnections)
!             on_proc_exit(log_disconnections, 0);
      }

      if (!IsUnderPostmaster)
      {
!         if (!userPGDATA)
          {
              write_stderr("%s does not know where to find the database system data.\n"
                           "You must specify the directory that contains the database system\n"
***************
*** 2588,2594 ****
                           argv[0]);
              proc_exit(1);
          }
!         SetDataDir(potential_DataDir);
      }
      Assert(DataDir);

--- 2588,2594 ----
                           argv[0]);
              proc_exit(1);
          }
!         SetDataDir(userPGDATA);
      }
      Assert(DataDir);

Index: src/backend/utils/misc/guc-file.l
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/guc-file.l,v
retrieving revision 1.22
diff -c -c -r1.22 guc-file.l
*** src/backend/utils/misc/guc-file.l    26 May 2004 15:07:38 -0000    1.22
--- src/backend/utils/misc/guc-file.l    11 Jul 2004 00:07:05 -0000
***************
*** 129,171 ****
   * function does not return if an error occurs. If an error occurs, no
   * values will be changed.
   */
! void
! ProcessConfigFile(GucContext context)
  {
      int token, parse_state;
      char *opt_name, *opt_value;
-     char *filename;
      struct name_value_pair *item, *head, *tail;
      int elevel;
      FILE * fp;

-     Assert(context == PGC_POSTMASTER || context == PGC_BACKEND
-         || context == PGC_SIGHUP);
-     Assert(DataDir);
      elevel = (context == PGC_SIGHUP) ? DEBUG4 : ERROR;

-     /*
-      * Open file
-      */
-     filename = malloc(strlen(DataDir) + strlen(CONFIG_FILENAME) + 2);
-     if (filename == NULL)
-     {
-         ereport(elevel,
-                 (errcode(ERRCODE_OUT_OF_MEMORY),
-                  errmsg("out of memory")));
-         return;
-     }
-     sprintf(filename, "%s/" CONFIG_FILENAME, DataDir);
-
      fp = AllocateFile(filename, "r");
      if (!fp)
      {
          free(filename);
!         /* File not found is fine */
!         if (errno != ENOENT)
!             ereport(elevel,
!                     (errcode_for_file_access(),
!                      errmsg("could not open configuration file \"%s\": %m", CONFIG_FILENAME)));
          return;
      }

--- 129,152 ----
   * function does not return if an error occurs. If an error occurs, no
   * values will be changed.
   */
! static void
! ReadConfigFile(char *filename, GucContext context)
  {
      int token, parse_state;
      char *opt_name, *opt_value;
      struct name_value_pair *item, *head, *tail;
      int elevel;
      FILE * fp;

      elevel = (context == PGC_SIGHUP) ? DEBUG4 : ERROR;

      fp = AllocateFile(filename, "r");
      if (!fp)
      {
          free(filename);
!         ereport(elevel,
!             (errcode_for_file_access(),
!              errmsg("could not open configuration file \"%s\": %m", filename)));
          return;
      }

***************
*** 197,203 ****
                      token = yylex();

                  if (token != GUC_ID && token != GUC_STRING &&
!                     token != GUC_INTEGER && token != GUC_REAL &&
                      token != GUC_UNQUOTED_STRING)
                      goto parse_error;
                  opt_value = strdup(yytext);
--- 178,185 ----
                      token = yylex();

                  if (token != GUC_ID && token != GUC_STRING &&
!                     token != GUC_INTEGER &&
!                     token != GUC_REAL &&
                      token != GUC_UNQUOTED_STRING)
                      goto parse_error;
                  opt_value = strdup(yytext);
***************
*** 259,265 ****
          }

      FreeFile(fp);
-     free(filename);

      /*
       * Check if all options are valid
--- 241,246 ----
***************
*** 282,293 ****

   parse_error:
      FreeFile(fp);
-     free(filename);
      free_name_value_list(head);
      ereport(elevel,
              (errcode(ERRCODE_SYNTAX_ERROR),
               errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
!                     CONFIG_FILENAME, ConfigFileLineno, yytext)));
      return;

   out_of_memory:
--- 263,273 ----

   parse_error:
      FreeFile(fp);
      free_name_value_list(head);
      ereport(elevel,
              (errcode(ERRCODE_SYNTAX_ERROR),
               errmsg("syntax error in file \"%s\" line %u, near token \"%s\"",
!                     filename, ConfigFileLineno, yytext)));
      return;

   out_of_memory:
***************
*** 298,303 ****
--- 278,342 ----
              (errcode(ERRCODE_OUT_OF_MEMORY),
               errmsg("out of memory")));
      return;
+ }
+
+ /*
+  * Function to read and process the configuration file. The
+  * parameter indicates the context that the file is being read
+  * (postmaster startup, backend startup, or SIGHUP). All options
+  * mentioned in the configuration file are set to new values. This
+  * function does not return if an error occurs. If an error occurs, no
+  * values will be changed.
+  */
+ void
+ ProcessConfigFile(GucContext context)
+ {
+     char *filename;
+
+     Assert(context == PGC_POSTMASTER || context == PGC_BACKEND || context == PGC_SIGHUP);
+
+     /* Added for explicit config file */
+     if (user_pgconfig)
+     {
+         struct stat sb;
+
+         if (stat(user_pgconfig, &sb) != 0)
+         {
+             int elevel = (context == PGC_SIGHUP) ? DEBUG3 : ERROR;
+             elog(elevel, "Configuration file \"%s\" does not exist", user_pgconfig);
+             return;
+         }
+
+         if (S_ISDIR(sb.st_mode))
+         {
+             /* This will cause a small one time memory leak
+              * if the user also specifies hba_conf,
+              * ident_conf, and data_dir
+              */
+             filename = malloc(strlen(user_pgconfig) + strlen(CONFIG_FILENAME) + 2);
+             sprintf(filename, "%s/%s", user_pgconfig, CONFIG_FILENAME);
+             user_pgconfig_is_dir = true;
+         }
+         else
+             filename = strdup(user_pgconfig);    /* Use explicit file */
+     }
+     else
+     {
+         /* Use datadir for config */
+         filename = malloc(strlen(DataDir) + strlen(CONFIG_FILENAME) + 2);
+         sprintf(filename, "%s/%s", DataDir, CONFIG_FILENAME);
+     }
+
+     if (filename == NULL)
+     {
+         int elevel = (context == PGC_SIGHUP) ? DEBUG3 : ERROR;
+         elog(elevel, "out of memory");
+         return;
+     }
+
+     ReadConfigFile(filename, context);
+
+     free(filename);
  }


Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v
retrieving revision 1.213
diff -c -c -r1.213 guc.c
*** src/backend/utils/misc/guc.c    5 Jul 2004 23:14:14 -0000    1.213
--- src/backend/utils/misc/guc.c    11 Jul 2004 00:07:08 -0000
***************
*** 57,62 ****
--- 57,69 ----
  #include "utils/pg_locale.h"
  #include "pgstat.h"

+ char *guc_pgdata;
+ char *guc_hbafile;
+ char *guc_identfile;
+ char *external_pidfile;
+
+ char *user_pgconfig = NULL;
+ bool user_pgconfig_is_dir = false;

  #ifndef PG_KRB_SRVTAB
  #define PG_KRB_SRVTAB ""
***************
*** 107,112 ****
--- 114,120 ----
  static bool assign_log_stats(bool newval, bool doit, GucSource source);
  static bool assign_transaction_read_only(bool newval, bool doit, GucSource source);

+ static void ReadConfigFile(char *filename, GucContext context);

  /*
   * Debugging options
***************
*** 1701,1715 ****
          NULL, assign_custom_variable_classes, NULL
      },

      /* End-of-list marker */
      {
          {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
      }
  };

- /******** end of options list ********/


  /*
   * To allow continued support of obsolete names for GUC variables, we apply
   * the following mappings to any unrecognized name.  Note that an old name
--- 1709,1748 ----
          NULL, assign_custom_variable_classes, NULL
      },

+     {
+         {"pgdata", PGC_POSTMASTER, 0, gettext_noop("Sets the location of the data directory"), NULL},
+         &guc_pgdata,
+         NULL, NULL, NULL
+     },
+
+     {
+         {"hba_conf", PGC_SIGHUP, 0, gettext_noop("Sets the location of the \"hba\" configuration file"), NULL},
+         &guc_hbafile,
+         NULL, NULL, NULL
+     },
+
+     {
+         {"ident_conf", PGC_SIGHUP, 0, gettext_noop("Sets the location of the \"ident\" configuration file"), NULL},
+         &guc_identfile,
+         NULL, NULL, NULL
+     },
+
+     {
+         {"external_pidfile", PGC_POSTMASTER, 0, gettext_noop("Writes the postmaster PID to the specified file"),
NULL},
+         &external_pidfile,
+         NULL, NULL, NULL
+     },
+
      /* End-of-list marker */
      {
          {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
      }
  };


+ /******** end of options list ********/

+
  /*
   * To allow continued support of obsolete names for GUC variables, we apply
   * the following mappings to any unrecognized name.  Note that an old name
Index: src/backend/utils/misc/postgresql.conf.sample
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/postgresql.conf.sample,v
retrieving revision 1.113
diff -c -c -r1.113 postgresql.conf.sample
*** src/backend/utils/misc/postgresql.conf.sample    7 Apr 2004 05:05:50 -0000    1.113
--- src/backend/utils/misc/postgresql.conf.sample    11 Jul 2004 00:07:09 -0000
***************
*** 22,27 ****
--- 22,37 ----


  #---------------------------------------------------------------------------
+ # CONFIGURATION FILES
+ #---------------------------------------------------------------------------
+
+ # pgdata = '/usr/local/pgsql/data'        # use data in another directory
+ # hba_conf = '/etc/pgsql/pg_hba.conf'         # use hba info in another directory
+ # ident_conf = '/etc/pgsql/pg_ident.conf'    # use ident info in another directory
+ # external_pidfile= '/var/run/postgresql.pid'    # write an extra pid file
+
+
+ #---------------------------------------------------------------------------
  # CONNECTIONS AND AUTHENTICATION
  #---------------------------------------------------------------------------

Index: src/include/utils/guc.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/utils/guc.h,v
retrieving revision 1.48
diff -c -c -r1.48 guc.h
*** src/include/utils/guc.h    1 Jul 2004 00:51:44 -0000    1.48
--- src/include/utils/guc.h    11 Jul 2004 00:07:10 -0000
***************
*** 135,140 ****
--- 135,147 ----
  extern int    client_min_messages;
  extern int    log_min_duration_statement;

+ extern char *guc_pgdata;
+ extern char *guc_hbafile;
+ extern char *guc_identfile;
+ extern char *external_pidfile;
+
+ extern char *user_pgconfig;
+ extern bool user_pgconfig_is_dir;

  extern void SetConfigOption(const char *name, const char *value,
                  GucContext context, GucSource source);

pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: build infrastructure for extensions v3
Next
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] Configuration patch