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.

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

[EMAIL PROTECTED] 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
  [EMAIL PROTECTED]               |  (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
  };
  
  /*
---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
    (send "unregister YourEmailAddressHere" to [EMAIL PROTECTED])

Reply via email to