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

From Bruce Momjian
Subject Re: [HACKERS] Configuration patch
Date
Msg-id 200406022040.i52Ke5T24083@candle.pha.pa.us
Whole thread Raw
In response to Configuration patch  (pgsql@mohawksoft.com)
Responses Re: [HACKERS] Configuration patch
List pgsql-patches
Here is an updated version of your patch.  I removed the tablespace part
because we are going to have real tablespaces in 7.5 rather than
initlocation hacks.  I added documention of the new guc parameters, and
a paragraph in the postmaster manual page describing the new -D/PGDATA
behavior.  (Is that enough?)  I see a few malloc/strup's in the
guc-file.l patch, but they seem OK.  I cleaned up the patch to be more
intuitive in its use of variable names and structure.

I will apply it in a day or if I get other feedback.

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

pgsql@mohawksoft.com wrote:
> This patch incorporates a number of changes suggested by the group. The
> purpose of this patch is to move postgresql to a position where all
> configuration options are specified in one place. The postgresql.conf file
> could completely document a postgresql environment.
>
>
> It adds this functionality:
>
> The "-D' option will work as it always has if it is set to a standard
> postgresql database cluster directory. If it is set to a "postgresql.conf"
> file, it will use that file for configuration. If it is set to a directory
> which is not a cluster directory, i.e. "/somepath/etc" it will look for
> pg_hba.conf, pg_ident.conf, and postgresql.conf there.
>
> For postgresql to work only with a configuration file, some options have
> been added:
>
> include = '/etc/postgres/debug.conf'
> pgdata = '/vol01/postgres'
> hba_conf = '/etc/postgres/pg_hba_conf'
> ident_conf = '/etc/postgres/pg_ident.conf'
> runtime_pidfile = '/var/run/postgresql.conf'
> tablespace = '/somevol/somepath'
>
> "include" allows files with configuration parameters to be included.
>
> "pgdata" (used to be data_dir in old patch) tells PostgreSQL where it's
> database cluster directory is located.
>
> "hba_conf" tells PostgreSQL where to find pg_hba.conf file.
>
> "ident_conf" tells PostgreSQL where to find pg_ident.conf.
>
> "runtime_pidfile" tells postgres to write it's PID to a file that would be
> used by external applications. It is *NOT* the pid file which postgresql
> uses.
>
> "tablespace" allows postgresql to use alternate locations without
> environment variables. Using SIGHUP, tablespaces are reloaded. This allows
> you to add tablespaces to a running PostgreSQL process. (I know this has a
> limited lifetime, but it may make "CREATE DATABASE ... WITH LOCATION" a
> little bit more sane in the meantime.

--
  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.265
diff -c -c -r1.265 runtime.sgml
*** doc/src/sgml/runtime.sgml    26 May 2004 18:51:43 -0000    1.265
--- doc/src/sgml/runtime.sgml    2 Jun 2004 20:31:36 -0000
***************
*** 563,568 ****
--- 563,625 ----
      any desired selection condition.
     </para>

+    <sect2 id="runtime-config-configuration-files">
+     <title>Configuration Files</title>
+
+      <variablelist>
+
+      <varlistentry id="guc-include" xreflabel="include">
+       <term><varname>include</varname> (<type>string</type>)</term>
+       <listitem>
+        <para>
+          Specifies an additional file to read for configuration settings.
+        </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="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="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.49
diff -c -c -r1.49 postmaster.sgml
*** doc/src/sgml/ref/postmaster.sgml    23 Mar 2004 06:09:00 -0000    1.49
--- doc/src/sgml/ref/postmaster.sgml    2 Jun 2004 20:31:36 -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,92 ----
     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.
+    They typically point to a directory created by <application>
+    initdb</>.  However, for administrative flexibility, you can
+    point directly to a configuration file like <filename>postgresql.conf</>.
+    This file must then specify the location of data directory using
+    <filename>postgresql.conf</>'s variable <varname>pgdata</>.
+    You can also point to a directory containing just configuration files,
+    and use <filename>postgresql.conf</>'s <varname>pgdata</> to point
+    to the directory containing the remaining files.
    </para>
   </refsect1>

Index: src/backend/bootstrap/bootstrap.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/bootstrap/bootstrap.c,v
retrieving revision 1.182
diff -c -c -r1.182 bootstrap.c
*** src/backend/bootstrap/bootstrap.c    29 May 2004 22:48:18 -0000    1.182
--- src/backend/bootstrap/bootstrap.c    2 Jun 2004 20:31:37 -0000
***************
*** 213,219 ****
      char       *dbname;
      int            flag;
      int            xlogop = BS_XLOG_NOP;
!     char       *potential_DataDir = NULL;

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

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

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

      /* Ignore the initial -boot argument, if present */
***************
*** 253,259 ****
          switch (flag)
          {
              case 'D':
!                 potential_DataDir = optarg;
                  break;
              case 'd':
                  {
--- 252,258 ----
          switch (flag)
          {
              case 'D':
!                 userPGDATA = optarg;
                  break;
              case 'd':
                  {
***************
*** 327,333 ****

      if (!IsUnderPostmaster)
      {
!         if (!potential_DataDir)
          {
              fprintf(stderr,
                      gettext("%s does not know where to find the database system data.\n"
--- 326,332 ----

      if (!IsUnderPostmaster)
      {
!         if (!userPGDATA)
          {
              fprintf(stderr,
                      gettext("%s does not know where to find the database system data.\n"
***************
*** 337,343 ****
                      argv[0]);
              proc_exit(1);
          }
!         SetDataDir(potential_DataDir);
      }

      /* Validate we have been given a reasonable-looking DataDir */
--- 336,342 ----
                      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    2 Jun 2004 20:31:38 -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.401
diff -c -c -r1.401 postmaster.c
*** src/backend/postmaster/postmaster.c    30 May 2004 03:50:11 -0000    1.401
--- src/backend/postmaster/postmaster.c    2 Jun 2004 20:31:41 -0000
***************
*** 226,231 ****
--- 226,232 ----
   * 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);
***************
*** 303,309 ****
  {
      int            opt;
      int            status;
!     char       *potential_DataDir = NULL;
      int            i;

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

      progname = get_progname(argv[0]);
***************
*** 367,373 ****
       */
      InitializeGUCOptions();

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

      opterr = 1;

--- 368,374 ----
       */
      InitializeGUCOptions();

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

      opterr = 1;

***************
*** 392,398 ****
                  /* Can no longer set the backend executable file to use. */
                  break;
              case 'D':
!                 potential_DataDir = optarg;
                  break;
              case 'd':
                  {
--- 393,399 ----
                  /* Can no longer set the backend executable file to use. */
                  break;
              case 'D':
!                 userPGDATA = optarg;
                  break;
              case 'd':
                  {
***************
*** 521,533 ****
          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();
--- 522,565 ----
          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? */
!             checkDataDir(NULL);        /* throw error */
!
!         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();
***************
*** 839,844 ****
--- 871,902 ----
      ExitPostmaster(status != STATUS_OK);

      return 0;                    /* not reached */
+ }
+
+
+
+ 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;
  }


Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/tcop/postgres.c,v
retrieving revision 1.417
diff -c -c -r1.417 postgres.c
*** src/backend/tcop/postgres.c    29 May 2004 22:48:20 -0000    1.417
--- src/backend/tcop/postgres.c    2 Jun 2004 20:31:43 -0000
***************
*** 2137,2143 ****
  {
      int            flag;
      const char *dbname = NULL;
!     char       *potential_DataDir = NULL;
      bool        secure;
      int            errs = 0;
      int            debug_flag = 0;
--- 2137,2143 ----
  {
      int            flag;
      const char *dbname = NULL;
!     char       *userPGDATA = NULL;
      bool        secure;
      int            errs = 0;
      int            debug_flag = 0;
***************
*** 2208,2214 ****
      if (!IsUnderPostmaster)
      {
          InitializeGUCOptions();
!         potential_DataDir = getenv("PGDATA");
      }

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

      /* ----------------
***************
*** 2256,2262 ****

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

              case 'd':            /* debug level */
--- 2256,2262 ----

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

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

      if (!IsUnderPostmaster)
      {
!         if (!potential_DataDir)
          {
              fprintf(stderr,
                      gettext("%s does not know where to find the database system data.\n"
--- 2547,2558 ----
           * set up handler to log session end.
           */
          if (IsUnderPostmaster && Log_disconnections)
!             on_proc_exit(log_disconnections, 0);
      }

      if (!IsUnderPostmaster)
      {
!         if (!userPGDATA)
          {
              fprintf(stderr,
                      gettext("%s does not know where to find the database system data.\n"
***************
*** 2562,2568 ****
                      argv[0]);
              proc_exit(1);
          }
!         SetDataDir(potential_DataDir);
      }
      Assert(DataDir);

--- 2562,2568 ----
                      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    2 Jun 2004 20:31:44 -0000
***************
*** 129,162 ****
   * 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)
      {
--- 129,145 ----
   * 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)
      {
***************
*** 165,171 ****
          if (errno != ENOENT)
              ereport(elevel,
                      (errcode_for_file_access(),
!                      errmsg("could not open configuration file \"%s\": %m", CONFIG_FILENAME)));
          return;
      }

--- 148,154 ----
          if (errno != ENOENT)
              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);
--- 180,187 ----
                      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
--- 243,248 ----
***************
*** 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:
--- 265,275 ----

   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 ****
--- 280,344 ----
              (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.210
diff -c -c -r1.210 guc.c
*** src/backend/utils/misc/guc.c    30 May 2004 23:40:38 -0000    1.210
--- src/backend/utils/misc/guc.c    2 Jun 2004 20:31:47 -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 ""
***************
*** 106,111 ****
--- 113,119 ----
  static bool assign_stage_log_stats(bool newval, bool doit, GucSource source);
  static bool assign_log_stats(bool newval, bool doit, GucSource source);

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

  /*
   * Debugging options
***************
*** 174,179 ****
--- 182,194 ----
  static int    block_size;
  static bool integer_datetimes;

+ struct config_function
+ {
+     struct config_generic gen;
+     void (*function)(char *param, GucContext context);
+ };
+
+
  /* Macros for freeing malloc'd pointers only if appropriate to do so */
  /* Some of these tests are probably redundant, but be safe ... */
  #define SET_STRING_VARIABLE(rec, newval) \
***************
*** 336,342 ****
       /* PGC_BOOL */ "bool",
       /* PGC_INT */ "integer",
       /* PGC_REAL */ "real",
!      /* PGC_STRING */ "string"
  };


--- 351,358 ----
       /* PGC_BOOL */ "bool",
       /* PGC_INT */ "integer",
       /* PGC_REAL */ "real",
!      /* PGC_STRING */ "string",
!      /* PGC_FUNCTION */ "function"
  };


***************
*** 1739,1753 ****
          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
--- 1755,1800 ----
          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
      }
  };


+ static struct config_function ConfigureFunctions[] =
+ {
+         { {"include", PGC_POSTMASTER}, ReadConfigFile},
+         { {NULL,0}, 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
***************
*** 1837,1842 ****
--- 1884,1897 ----
          num_vars++;
      }

+     for(i = 0; ConfigureFunctions[i].gen.name; i++)
+     {
+         struct config_function *conf = &ConfigureFunctions[i];
+
+         conf->gen.vartype = PGC_FUNCTION;
+         num_vars++;
+     }
+
      /* Create table with 20% slack
       */
      size_vars = num_vars + num_vars / 4;
***************
*** 1862,1867 ****
--- 1917,1925 ----
      for (i = 0; ConfigureNamesString[i].gen.name; i++)
          guc_vars[num_vars++] = &ConfigureNamesString[i].gen;

+     for (i = 0; ConfigureFunctions[i].gen.name; i++)
+         guc_vars[num_vars++] = &ConfigureFunctions[i].gen;
+
      if (guc_variables)
          free(guc_variables);
      guc_variables = guc_vars;
***************
*** 2193,2198 ****
--- 2251,2258 ----
                      conf->session_val = str;
                      break;
                  }
+             case PGC_FUNCTION: /* Nothing to do */
+                 break;
          }
      }

***************
*** 2344,2349 ****
--- 2404,2411 ----
                      guc_dirty = true;
                      break;
                  }
+             case PGC_FUNCTION: /* Nothing to do */
+                 break;
          }

          if (gconf->flags & GUC_REPORT)
***************
*** 2500,2505 ****
--- 2562,2569 ----
                      conf->gen.status = 0;
                      break;
                  }
+             case    PGC_FUNCTION: /* Nothing to do */
+                 break;
          }

          if (changed && (gconf->flags & GUC_REPORT))
***************
*** 3301,3306 ****
--- 3365,3382 ----
                      free(newval);
                  break;
              }
+
+         case PGC_FUNCTION:
+             if (!changeVal)
+             {
+                 /* During the "checking" stage of configuration
+                  * read, run functions
+                  */
+                 struct config_function *fn =
+                     (struct config_function *)record;
+                 fn->function((char *)value, context);
+             }
+             break;
      }

      if (changeVal && (record->flags & GUC_REPORT))
***************
*** 3361,3366 ****
--- 3437,3446 ----

          case PGC_STRING:
              return *((struct config_string *) record)->variable;
+
+         case PGC_FUNCTION:
+             /* Should never really happen */
+             return NULL;
      }
      return NULL;
  }
***************
*** 3397,3402 ****
--- 3477,3486 ----

          case PGC_STRING:
              return ((struct config_string *) record)->reset_val;
+
+         case PGC_FUNCTION:
+             /* Should never really happen */
+             return NULL;
      }
      return NULL;
  }
***************
*** 4351,4356 ****
--- 4435,4443 ----
                          fprintf(fp, "%s", *conf->variable);
                      }
                      break;
+
+                 case PGC_FUNCTION:    /* do nothing */
+                     break;
              }

              fputc(0, fp);
***************
*** 5131,5133 ****
--- 5218,5221 ----


  #include "guc-file.c"
+
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    2 Jun 2004 20:31:47 -0000
***************
*** 22,27 ****
--- 22,38 ----


  #---------------------------------------------------------------------------
+ # CONFIGURATION FILES
+ #---------------------------------------------------------------------------
+
+ # include = '/somedir/pgdefs.conf'        # include another file
+ # hba_conf = '/etc/postgres/pg_hba.conf'     # use file in another directory
+ # ident_conf = '/etc/postgres/pg_ident.conf'    # use file in another directory
+ # pgdata = '/usr/local/pgsql/data'        # use /data 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.47
diff -c -c -r1.47 guc.h
*** src/include/utils/guc.h    28 May 2004 05:13:32 -0000    1.47
--- src/include/utils/guc.h    2 Jun 2004 20:31:48 -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);
Index: src/include/utils/guc_tables.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/utils/guc_tables.h,v
retrieving revision 1.11
diff -c -c -r1.11 guc_tables.h
*** src/include/utils/guc_tables.h    26 May 2004 15:07:41 -0000    1.11
--- src/include/utils/guc_tables.h    2 Jun 2004 20:31:48 -0000
***************
*** 63,69 ****
      PGC_BOOL,
      PGC_INT,
      PGC_REAL,
!     PGC_STRING
  };

  /*
--- 63,70 ----
      PGC_BOOL,
      PGC_INT,
      PGC_REAL,
!     PGC_STRING,
!     PGC_FUNCTION
  };

  /*

pgsql-patches by date:

Previous
From: Gaetano Mendola
Date:
Subject: Re: pg_ctl.c
Next
From: Bruce Momjian
Date:
Subject: Re: SET WITHOUT CLUSTER