diff --git a/doc/src/sgml/ref/postgres-ref.sgml b/doc/src/sgml/ref/postgres-ref.sgml
index cfb16a78686053fa7e9d8c5b3df978dbbe21ed65..b0a5f920a9e10f67d6daa67a09cb8b8af22731e0 100644
--- a/doc/src/sgml/ref/postgres-ref.sgml
+++ b/doc/src/sgml/ref/postgres-ref.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/postgres-ref.sgml,v 1.43 2004/02/03 17:34:02 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/postgres-ref.sgml,v 1.44 2004/10/08 01:36:32 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -357,7 +357,7 @@ PostgreSQL documentation
 
     <listitem>
      <para>
-      Default data direction location
+      Default data directory location
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/ref/postmaster.sgml b/doc/src/sgml/ref/postmaster.sgml
index d7255dc87f77a41fd1024903227d205fc08ddded..518f958e5192bccc69a06ad4dc31ee34b8ef23f0 100644
--- a/doc/src/sgml/ref/postmaster.sgml
+++ b/doc/src/sgml/ref/postmaster.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/postmaster.sgml,v 1.52 2004/09/20 00:04:19 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/postmaster.sgml,v 1.53 2004/10/08 01:36:32 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -67,27 +67,22 @@ PostgreSQL documentation
    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>).  
+   location (the <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
+   at one time, so 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
+   When the <command>postmaster</command> starts it needs 
+   to know the location of the data area.
+   The location must be 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</> variable 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.
+   Typically, <option>-D</option> or <envar>PGDATA</envar> points
+   directly to the data area directory created by <application>initdb</>.
+   Other possible file layouts are discussed in
+   <xref linkend="runtime-config-file-locations">.
   </para>
  </refsect1>
 
@@ -154,8 +149,9 @@ PostgreSQL documentation
       <term><option>-D <replaceable class="parameter">datadir</replaceable></option></term>
       <listitem>
        <para>
-	Specifies the file system location of the data directory.  See
-	discussion above.
+        Specifies the file system location of the data directory or
+        configuration file(s).  See
+        <xref linkend="runtime-config-file-locations"> for details.
        </para>
       </listitem>
      </varlistentry>
@@ -394,7 +390,7 @@ PostgreSQL documentation
 
     <listitem>
      <para>
-      Default data direction location
+      Default data directory location
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 22e75ae0eb324f61c7555d7ae0bfe7df2f762bc6..f6946a08e18799a1d3639bff01e3330825ba0a47 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.285 2004/09/29 06:27:11 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.286 2004/10/08 01:36:31 tgl Exp $
 -->
 
 <Chapter Id="runtime">
@@ -564,17 +564,16 @@ SET ENABLE_SEQSCAN TO OFF;
     any desired selection condition.
    </para>
     
-   <sect2 id="runtime-config-configuration-files">
-    <title>Configuration Files</title>
+   <sect2 id="runtime-config-file-locations">
+    <title>File Locations</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).
+         Specifies the directory to use for data storage.
+         This option can only be set at server start.
        </para>
       </listitem>
      </varlistentry>
@@ -585,6 +584,8 @@ SET ENABLE_SEQSCAN TO OFF;
        <para>
          Specifies the file name to use for configuration of host-based 
          authentication (HBA).
+         This option can only be set at server start or in the
+         <filename>postgresql.conf</filename> file.
        </para>
       </listitem>
      </varlistentry>
@@ -595,6 +596,8 @@ SET ENABLE_SEQSCAN TO OFF;
        <para>
          Specifies the file name to use for configuration of 
          <application>ident</> authentication.
+         This option can only be set at server start or in the
+         <filename>postgresql.conf</filename> file.
        </para>
       </listitem>
      </varlistentry>
@@ -605,11 +608,50 @@ SET ENABLE_SEQSCAN TO OFF;
        <para>
          Specifies the location of an additional <application>postmaster</>
          process-id (PID) file for use by server administration programs.
+         This option can only be set at server start.
        </para>
       </listitem>
      </varlistentry>
-
      </variablelist>
+
+     <para>
+      In a default installation, none of the above options is set explicitly
+      in the <filename>postgresql.conf</filename> file.  In this case, the
+      data directory is specified by the <option>-D</option> command-line
+      option or the <envar>PGDATA</envar> environment variable; there is no
+      default for it.  The configuration files are all placed within the
+      data directory.
+     </para>
+
+     <para>
+      It is also possible to separate the configuration files from the data
+      directory, which can ease administration.  (In particular it is often
+      easier to ensure that the configuration files are properly backed-up
+      when they are kept separate.)  To do this, the <option>-D</option>
+      command-line option or <envar>PGDATA</envar> environment variable
+      must point to the directory containing the configuration files,
+      and the <varname>pgdata</> option is set in
+      <filename>postgresql.conf</filename> (or on the command line) to show
+      where the data directory is actually located.
+     </para>
+
+     <para>
+      If you wish, you can also make the <option>-D</option>
+      command-line option or <envar>PGDATA</envar> environment variable
+      point directly to the master configuration file (which then need not be
+      named <filename>postgresql.conf</filename>).  The <varname>pgdata</>
+      option must be set to determine the data directory location.
+      The other configuration files will by default be sought
+      in the data directory.
+     </para>
+
+     <para>
+      With any of these approaches, you can specify the locations of the
+      secondary configuration files (<filename>pg_hba.conf</> and
+      <filename>pg_ident.conf</>) by setting <varname>hba_conf</> and/or
+      <varname>ident_conf</> in the master configuration file.  These options
+      override the normal locations and names of the secondary files.
+     </para>
    </sect2>
 
    <sect2 id="runtime-config-connection">
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 0b63df18012ba02b782f736cf445eeecd2390a34..d85692cb62fefe34a4e64bfef7830a4d73d7c84f 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.193 2004/08/29 05:06:41 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.194 2004/10/08 01:36:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -210,7 +210,7 @@ BootstrapMain(int argc, char *argv[])
 	char	   *dbname;
 	int			flag;
 	int			xlogop = BS_XLOG_NOP;
-	char	   *userPGDATA = NULL;
+	char	   *userDoption = NULL;
 
 	/*
 	 * initialize globals
@@ -240,10 +240,7 @@ BootstrapMain(int argc, char *argv[])
 	/* Set defaults, to be overriden by explicit options below */
 	dbname = NULL;
 	if (!IsUnderPostmaster)
-	{
 		InitializeGUCOptions();
-		userPGDATA = getenv("PGDATA");	/* Null if no PGDATA variable */
-	}
 
 	/* Ignore the initial -boot argument, if present */
 	if (argc > 1 && strcmp(argv[1], "-boot") == 0)
@@ -257,7 +254,7 @@ BootstrapMain(int argc, char *argv[])
 		switch (flag)
 		{
 			case 'D':
-				userPGDATA = optarg;
+				userDoption = optarg;
 				break;
 			case 'd':
 				{
@@ -328,24 +325,6 @@ BootstrapMain(int argc, char *argv[])
 	if (!dbname || argc != optind)
 		usage();
 
-	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"
-						 "either by specifying the -D invocation option or by setting the\n"
-						 "PGDATA environment variable.\n",
-						 argv[0]);
-			proc_exit(1);
-		}
-		SetDataDir(userPGDATA);
-	}
-
-	/* Validate we have been given a reasonable-looking DataDir */
-	Assert(DataDir);
-	ValidatePgVersion(DataDir);
-
 	/*
 	 * Identify myself via ps
 	 */
@@ -372,12 +351,14 @@ BootstrapMain(int argc, char *argv[])
 	/* Acquire configuration parameters, unless inherited from postmaster */
 	if (!IsUnderPostmaster)
 	{
-		ProcessConfigFile(PGC_POSTMASTER);
-
-		/* If timezone is not set, determine what the OS uses */
-		pg_timezone_initialize();
+		if (!SelectConfigFiles(userDoption, argv[0]))
+			proc_exit(1);
 	}
 
+	/* Validate we have been given a reasonable-looking DataDir */
+	Assert(DataDir);
+	ValidatePgVersion(DataDir);
+
 	/* If standalone, create lockfile for data directory */
 	if (!IsUnderPostmaster)
 		CreateDataDirLockFile(DataDir, false);
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 6e761b10a753fdb9433d615c85616f6091c3a6d6..0699868bfab1b00d6f976968f54a1599d05175a1 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.130 2004/09/18 01:22:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.131 2004/10/08 01:36:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1044,16 +1044,16 @@ load_hba(void)
 	if (hba_lines || hba_line_nums)
 		free_lines(&hba_lines, &hba_line_nums);
 
-	/* HBA filename in config file */
 	if (guc_hbafile)
+	{
+		/* HBA filename specified in config file */
 		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);
+		conf_file = palloc(strlen(ConfigDir) + strlen(CONF_FILE) + 2);
+		sprintf(conf_file, "%s/%s", ConfigDir, CONF_FILE);
 	}
 
 	file = AllocateFile(conf_file, "r");
@@ -1198,16 +1198,15 @@ load_ident(void)
 	if (ident_lines || ident_line_nums)
 		free_lines(&ident_lines, &ident_line_nums);
 
-	/* IDENT filename in config file */
 	if (guc_identfile)
+	{
+		/* IDENT filename specified in config file */
 		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);
+		map_file = palloc(strlen(ConfigDir) + strlen(USERMAP_FILE) + 2);
+		sprintf(map_file, "%s/%s", ConfigDir, USERMAP_FILE);
 	}
 
 	file = AllocateFile(map_file, "r");
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 3091fb2dc5abec57174b567c4ffacbaf25a921d7..95e74eb30b567369cf60d57f50c6384da4ed99b8 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.429 2004/10/07 17:04:54 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.430 2004/10/08 01:36:34 tgl Exp $
  *
  * NOTES
  *
@@ -236,8 +236,7 @@ extern int	optreset;
 /*
  * postmaster.c - function prototypes
  */
-static void checkDataDir(const char *checkdir);
-static bool onlyConfigSpecified(const char *checkdir);
+static void checkDataDir(void);
 
 #ifdef USE_RENDEZVOUS
 static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode,
@@ -311,7 +310,7 @@ PostmasterMain(int argc, char *argv[])
 {
 	int			opt;
 	int			status;
-	char	   *userPGDATA = NULL;
+	char	   *userDoption = NULL;
 	int			i;
 
 	progname = get_progname(argv[0]);
@@ -375,8 +374,6 @@ PostmasterMain(int argc, char *argv[])
 	 */
 	InitializeGUCOptions();
 
-	userPGDATA = getenv("PGDATA");		/* default value */
-
 	opterr = 1;
 
 	while ((opt = getopt(argc, argv, "A:a:B:b:c:D:d:Fh:ik:lm:MN:no:p:Ss-:")) != -1)
@@ -400,7 +397,7 @@ PostmasterMain(int argc, char *argv[])
 				/* Can no longer set the backend executable file to use. */
 				break;
 			case 'D':
-				userPGDATA = optarg;
+				userDoption = optarg;
 				break;
 			case 'd':
 				{
@@ -530,61 +527,15 @@ PostmasterMain(int argc, char *argv[])
 		ExitPostmaster(1);
 	}
 
-	if (userPGDATA)
-	{
-		userPGDATA = strdup(userPGDATA);
-		canonicalize_path(userPGDATA);
-	}
-
-	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);
-	}
+	/*
+	 * Locate the proper configuration files and data directory, and
+	 * read postgresql.conf for the first time.
+	 */
+	if (!SelectConfigFiles(userDoption, progname))
+		ExitPostmaster(2);
 
-	/* If timezone is not set, determine what the OS uses */
-	pg_timezone_initialize();
+	/* Verify that DataDir looks reasonable */
+	checkDataDir();
 
 #ifdef EXEC_BACKEND
 	write_nondefault_variables(PGC_POSTMASTER);
@@ -831,6 +782,24 @@ PostmasterMain(int argc, char *argv[])
 	if (!CreateOptsFile(argc, argv, my_exec_path))
 		ExitPostmaster(1);
 
+	/*
+	 * Write the external PID file if requested
+	 */
+	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
+			write_stderr("%s: could not write external pid file \"%s\": %s\n",
+						 progname, external_pidfile, strerror(errno));
+	}
+
 	/*
 	 * Set up signal handlers for the postmaster process.
 	 *
@@ -907,66 +876,30 @@ PostmasterMain(int argc, char *argv[])
 }
 
 
-
-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
  */
 static void
-checkDataDir(const char *checkdir)
+checkDataDir(void)
 {
 	char		path[MAXPGPATH];
 	FILE	   *fp;
 	struct stat stat_buf;
 
-	if (checkdir == NULL)
-	{
-		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);
-	}
+	Assert(DataDir);
 
-	if (stat(checkdir, &stat_buf) == -1)
+	if (stat(DataDir, &stat_buf) != 0)
 	{
 		if (errno == ENOENT)
 			ereport(FATAL,
 					(errcode_for_file_access(),
 					 errmsg("data directory \"%s\" does not exist",
-							checkdir)));
+							DataDir)));
 		else
 			ereport(FATAL,
 					(errcode_for_file_access(),
 			 errmsg("could not read permissions of directory \"%s\": %m",
-					checkdir)));
+					DataDir)));
 	}
 
 	/*
@@ -981,14 +914,14 @@ checkDataDir(const char *checkdir)
 		ereport(FATAL,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("data directory \"%s\" has group or world access",
-						checkdir),
+						DataDir),
 				 errdetail("Permissions should be u=rwx (0700).")));
 #endif
 
 	/* Look for PG_VERSION before looking for pg_control */
-	ValidatePgVersion(checkdir);
+	ValidatePgVersion(DataDir);
 
-	snprintf(path, sizeof(path), "%s/global/pg_control", checkdir);
+	snprintf(path, sizeof(path), "%s/global/pg_control", DataDir);
 
 	fp = AllocateFile(path, PG_BINARY_R);
 	if (fp == NULL)
@@ -996,7 +929,7 @@ checkDataDir(const char *checkdir)
 		write_stderr("%s: could not find the database system\n"
 					 "Expected to find it in the directory \"%s\",\n"
 					 "but could not open file \"%s\": %s\n",
-					 progname, checkdir, path, strerror(errno));
+					 progname, DataDir, path, strerror(errno));
 		ExitPostmaster(2);
 	}
 	FreeFile(fp);
@@ -3457,6 +3390,12 @@ write_backend_variables(char *filename, Port *port)
 	StrNCpy(str_buf, DataDir, MAXPGPATH);
 	write_array_var(str_buf, fp);
 
+	StrNCpy(str_buf, ConfigDir, MAXPGPATH);
+	write_array_var(str_buf, fp);
+
+	StrNCpy(str_buf, ConfigFileName, MAXPGPATH);
+	write_array_var(str_buf, fp);
+
 	write_array_var(ListenSocket, fp);
 
 	write_var(MyCancelKey, fp);
@@ -3531,6 +3470,12 @@ read_backend_variables(char *filename, Port *port)
 	read_array_var(str_buf, fp);
 	SetDataDir(str_buf);
 
+	read_array_var(str_buf, fp);
+	ConfigDir = strdup(str_buf);
+
+	read_array_var(str_buf, fp);
+	ConfigFileName = strdup(str_buf);
+
 	read_array_var(ListenSocket, fp);
 
 	read_var(MyCancelKey, fp);
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 5658e10d4533183d5197f202e6cd073a2784adcf..1c668445519c73def4b7c2a8d1f9dbe0e0c29af2 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.433 2004/09/26 00:26:25 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.434 2004/10/08 01:36:35 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -2156,7 +2156,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 {
 	int			flag;
 	const char *dbname = NULL;
-	char	   *userPGDATA = NULL;
+	char	   *userDoption = NULL;
 	bool		secure;
 	int			errs = 0;
 	int			debug_flag = 0;
@@ -2226,10 +2226,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 	EchoQuery = false;
 
 	if (!IsUnderPostmaster)
-	{
 		InitializeGUCOptions();
-		userPGDATA = getenv("PGDATA");
-	}
 
 	/* ----------------
 	 *	parse command line arguments
@@ -2274,9 +2271,9 @@ PostgresMain(int argc, char *argv[], const char *username)
 				SetConfigOption("shared_buffers", optarg, ctx, gucsource);
 				break;
 
-			case 'D':			/* PGDATA directory */
+			case 'D':			/* PGDATA or config directory */
 				if (secure)
-					userPGDATA = optarg;
+					userDoption = optarg;
 				break;
 
 			case 'd':			/* debug level */
@@ -2571,28 +2568,11 @@ PostgresMain(int argc, char *argv[], const char *username)
 			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"
-						 "either by specifying the -D invocation option or by setting the\n"
-						 "PGDATA environment variable.\n",
-						 argv[0]);
-			proc_exit(1);
-		}
-		SetDataDir(userPGDATA);
-	}
-	Assert(DataDir);
-
 	/* Acquire configuration parameters, unless inherited from postmaster */
 	if (!IsUnderPostmaster)
 	{
-		ProcessConfigFile(PGC_POSTMASTER);
-
-		/* If timezone is not set, determine what the OS uses */
-		pg_timezone_initialize();
+		if (!SelectConfigFiles(userDoption, argv[0]))
+			proc_exit(1);
 	}
 
 	/*
@@ -2685,6 +2665,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 		 * Validate we have been given a reasonable-looking DataDir (if
 		 * under postmaster, assume postmaster did this already).
 		 */
+		Assert(DataDir);
 		ValidatePgVersion(DataDir);
 
 		/*
diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l
index 86f50359997b11a6a8a3b9973dacf8155bcfc2d2..913dead8303cd0c42226309a500cf526cb42e38e 100644
--- a/src/backend/utils/misc/guc-file.l
+++ b/src/backend/utils/misc/guc-file.l
@@ -4,14 +4,13 @@
  *
  * Copyright (c) 2000-2004, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.25 2004/08/31 22:43:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc-file.l,v 1.26 2004/10/08 01:36:35 tgl Exp $
  */
 
 %{
 
 #include "postgres.h"
 
-#include <sys/stat.h>
 #include <unistd.h>
 #include <ctype.h>
 
@@ -22,8 +21,6 @@
 /* Avoid exit() on fatal scanner errors (a bit ugly -- see yy_fatal_error) */
 #define fprintf(file, fmt, msg)  ereport(ERROR, (errmsg_internal("%s", msg)))
 
-#define CONFIG_FILENAME "postgresql.conf"
-
 static unsigned ConfigFileLineno;
 
 enum {
@@ -128,7 +125,6 @@ void
 ProcessConfigFile(GucContext context)
 {
 	int			elevel;
-	char	   *filename;
 	int			token, parse_state;
 	char	   *opt_name, *opt_value;
 	struct name_value_pair *item, *head, *tail;
@@ -147,46 +143,13 @@ ProcessConfigFile(GucContext context)
 	else
 		elevel = ERROR;
 
-	/*
-	 * Handle the various possibilities for config file location
-	 */
-	if (user_pgconfig)
-	{
-		struct stat sb;
-
-		if (stat(user_pgconfig, &sb) != 0)
-		{
-			ereport(elevel,
-					(errcode_for_file_access(),
-					 errmsg("could not access configuration file \"%s\": %m",
-							user_pgconfig)));
-			return;
-		}
-
-		if (S_ISDIR(sb.st_mode))
-		{
-			filename = palloc(strlen(user_pgconfig) + strlen(CONFIG_FILENAME) + 2);
-			sprintf(filename, "%s/%s", user_pgconfig, CONFIG_FILENAME);
-			user_pgconfig_is_dir = true;
-		}
-		else
-			filename = pstrdup(user_pgconfig);	/* Use explicit file */
-	}
-	else
-	{
-		/* Find config in datadir */
-		filename = palloc(strlen(DataDir) + strlen(CONFIG_FILENAME) + 2);
-		sprintf(filename, "%s/%s", DataDir, CONFIG_FILENAME);
-	}
-
-    fp = AllocateFile(filename, "r");
+    fp = AllocateFile(ConfigFileName, "r");
     if (!fp)
     {
 		ereport(elevel,
 				(errcode_for_file_access(),
 				 errmsg("could not open configuration file \"%s\": %m",
-						filename)));
-		pfree(filename);
+						ConfigFileName)));
 		return;
     }
 
@@ -273,7 +236,6 @@ ProcessConfigFile(GucContext context)
 	}
 
 	FreeFile(fp);
-	pfree(filename);
 
 	/*
 	 * Check if all options are valid
@@ -303,13 +265,12 @@ ProcessConfigFile(GucContext context)
 		ereport(elevel,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("syntax error in file \"%s\" line %u, near end of line",
-						filename, ConfigFileLineno - 1)));
+						ConfigFileName, ConfigFileLineno - 1)));
 	else
 		ereport(elevel,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("syntax error in file \"%s\" line %u, near token \"%s\"", 
-						filename, ConfigFileLineno, yytext)));
-	pfree(filename);
+						ConfigFileName, ConfigFileLineno, yytext)));
 }
 
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 4fb2fad4a6b485a68b095b86db3190b1d512d928..8e2deeeb007aaff3e5cc34e4afeddfd27e3ee6f0 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.239 2004/09/24 19:43:03 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.240 2004/10/08 01:36:35 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -20,6 +20,7 @@
 #include <float.h>
 #include <limits.h>
 #include <unistd.h>
+#include <sys/stat.h>
 
 #include "utils/guc.h"
 #include "utils/guc_tables.h"
@@ -58,18 +59,13 @@
 #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 ""
 #endif
 
+#define CONFIG_FILENAME "postgresql.conf"
+
 #ifdef EXEC_BACKEND
 #define CONFIG_EXEC_PARAMS "global/config_exec_params"
 #endif
@@ -118,7 +114,14 @@ static const char *assign_canonical_path(const char *newval, bool doit, GucSourc
 
 
 /*
- * Debugging options
+ * These are initialized by SelectConfigFiles.
+ */
+char	   *ConfigDir = NULL;
+char	   *ConfigFileName = NULL;
+
+
+/*
+ * GUC option variables that are exported from this module
  */
 #ifdef USE_ASSERT_CHECKING
 bool		assert_enabled = true;
@@ -151,6 +154,10 @@ int			client_min_messages = NOTICE;
 
 int			log_min_duration_statement = -1;
 
+char	   *guc_hbafile;
+char	   *guc_identfile;
+char	   *external_pidfile;
+
 
 /*
  * These variables are all dummies that don't do anything, except in some
@@ -176,6 +183,7 @@ static char *server_encoding_string;
 static char *server_version_string;
 static char *timezone_string;
 static char *XactIsoLevel_string;
+static char *guc_pgdata;
 static char *custom_variable_classes;
 static int	max_function_args;
 static int	max_index_keys;
@@ -231,6 +239,8 @@ const char *const config_group_names[] =
 {
 	/* UNGROUPED */
 	gettext_noop("Ungrouped"),
+	/* FILE_LOCATIONS */
+	gettext_noop("File Locations"),
 	/* CONN_AUTH */
 	gettext_noop("Connections and Authentication"),
 	/* CONN_AUTH_SETTINGS */
@@ -291,10 +301,12 @@ const char *const config_group_names[] =
 	gettext_noop("Version and Platform Compatibility / Previous PostgreSQL Versions"),
 	/* COMPAT_OPTIONS_CLIENT */
 	gettext_noop("Version and Platform Compatibility / Other Platforms and Clients"),
+	/* PRESET_OPTIONS */
+	gettext_noop("Preset Options"),
+	/* CUSTOM_OPTIONS */
+	gettext_noop("Customized Options"),
 	/* DEVELOPER_OPTIONS */
 	gettext_noop("Developer Options"),
-	/* COMPILE_OPTIONS */
-	gettext_noop("Compiled-in Options"),
 	/* help_config wants this array to be null-terminated */
 	NULL
 };
@@ -833,7 +845,7 @@ static struct config_bool ConfigureNamesBool[] =
 #endif
 
 	{
-		{"integer_datetimes", PGC_INTERNAL, COMPILE_OPTIONS,
+		{"integer_datetimes", PGC_INTERNAL, PRESET_OPTIONS,
 			gettext_noop("Datetimes are integer based"),
 			NULL,
 			GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
@@ -1282,7 +1294,7 @@ static struct config_int ConfigureNamesInt[] =
 	},
 
 	{
-		{"max_function_args", PGC_INTERNAL, COMPILE_OPTIONS,
+		{"max_function_args", PGC_INTERNAL, PRESET_OPTIONS,
 			gettext_noop("Shows the maximum number of function arguments"),
 			NULL,
 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
@@ -1292,7 +1304,7 @@ static struct config_int ConfigureNamesInt[] =
 	},
 
 	{
-		{"max_index_keys", PGC_INTERNAL, COMPILE_OPTIONS,
+		{"max_index_keys", PGC_INTERNAL, PRESET_OPTIONS,
 			gettext_noop("Shows the maximum number of index keys"),
 			NULL,
 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
@@ -1302,7 +1314,7 @@ static struct config_int ConfigureNamesInt[] =
 	},
 
 	{
-		{"max_identifier_length", PGC_INTERNAL, COMPILE_OPTIONS,
+		{"max_identifier_length", PGC_INTERNAL, PRESET_OPTIONS,
 			gettext_noop("Shows the maximum identifier length"),
 			NULL,
 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
@@ -1312,7 +1324,7 @@ static struct config_int ConfigureNamesInt[] =
 	},
 
 	{
-		{"block_size", PGC_INTERNAL, COMPILE_OPTIONS,
+		{"block_size", PGC_INTERNAL, PRESET_OPTIONS,
 			gettext_noop("Shows size of a disk block"),
 			NULL,
 			GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
@@ -1640,7 +1652,7 @@ static struct config_string ConfigureNamesString[] =
 
 	{
 		/* Can't be set in postgresql.conf */
-		{"server_version", PGC_INTERNAL, UNGROUPED,
+		{"server_version", PGC_INTERNAL, PRESET_OPTIONS,
 			gettext_noop("Shows the server version."),
 			NULL,
 			GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
@@ -1777,25 +1789,37 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"pgdata", PGC_POSTMASTER, 0, gettext_noop("Sets the location of the data directory"), NULL},
+		{"pgdata", PGC_POSTMASTER, FILE_LOCATIONS,
+		 gettext_noop("Sets the location of the data directory"),
+		 NULL
+		},
 		&guc_pgdata,
 		NULL, assign_canonical_path, NULL
 	},
 
 	{
-		{"hba_conf", PGC_SIGHUP, 0, gettext_noop("Sets the location of the \"hba\" configuration file"), NULL},
+		{"hba_conf", PGC_SIGHUP, FILE_LOCATIONS,
+		 gettext_noop("Sets the location of the \"hba\" configuration file"),
+		 NULL
+		},
 		&guc_hbafile,
 		NULL, assign_canonical_path, NULL
 	},
 
 	{
-		{"ident_conf", PGC_SIGHUP, 0, gettext_noop("Sets the location of the \"ident\" configuration file"), NULL},
+		{"ident_conf", PGC_SIGHUP, FILE_LOCATIONS,
+		 gettext_noop("Sets the location of the \"ident\" configuration file"),
+		 NULL
+		},
 		&guc_identfile,
 		NULL, assign_canonical_path, NULL
 	},
 
 	{
-		{"external_pidfile", PGC_POSTMASTER, 0, gettext_noop("Writes the postmaster PID to the specified file"), NULL},
+		{"external_pidfile", PGC_POSTMASTER, FILE_LOCATIONS,
+		 gettext_noop("Writes the postmaster PID to the specified file"),
+		 NULL
+		},
 		&external_pidfile,
 		NULL, assign_canonical_path, NULL
 	},
@@ -2247,6 +2271,9 @@ guc_name_compare(const char *namea, const char *nameb)
 
 /*
  * Initialize GUC options during program startup.
+ *
+ * Note that we cannot read the config file yet, since we have not yet
+ * processed command-line switches.
  */
 void
 InitializeGUCOptions(void)
@@ -2412,6 +2439,102 @@ InitializeGUCOptions(void)
 }
 
 
+/*
+ * Select the configuration files and data directory to be used, and
+ * do the initial read of postgresql.conf.
+ *
+ * This is called after processing command-line switches.
+ *		userDoption is the -D switch value if any (NULL if unspecified).
+ *		progname is just for use in error messages.
+ *
+ * Returns true on success; on failure, prints a suitable error message
+ * to stderr and returns false.
+ */
+bool
+SelectConfigFiles(const char *userDoption, const char *progname)
+{
+	char   *Doption;
+	struct stat stat_buf;
+
+	/* If user did not specify -D, it defaults to $PGDATA */
+	if (!userDoption)
+		userDoption = getenv("PGDATA");
+
+	/* If no PGDATA either, we are completely lost */
+	if (!userDoption)
+	{
+		write_stderr("%s does not know where to find the database system data.\n"
+					 "You must specify the -D invocation option or set the "
+					 "PGDATA environment variable.\n",
+					 progname);
+		return false;
+	}
+
+	/* Get a writable copy and canonicalize the path */
+	Doption = guc_strdup(FATAL, userDoption);
+	canonicalize_path(Doption);
+
+	/*
+	 * If it is a directory, point ConfigDir to it, and expect to
+	 * find postgresql.conf within.  Otherwise it had better be
+	 * the actual config file, and the file had better set "pgdata".
+	 */
+	if (stat(Doption, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode))
+	{
+		ConfigDir = Doption;
+		ConfigFileName = guc_malloc(FATAL,
+							strlen(ConfigDir) + strlen(CONFIG_FILENAME) + 2);
+		sprintf(ConfigFileName, "%s/%s", ConfigDir, CONFIG_FILENAME);
+	}
+	else
+	{
+		ConfigFileName = Doption;
+	}
+
+	if (stat(ConfigFileName, &stat_buf) != 0)
+	{
+		write_stderr("%s cannot access the data directory or configuration file \"%s\": %s\n",
+					 progname, ConfigFileName, strerror(errno));
+		return false;
+	}
+
+	ProcessConfigFile(PGC_POSTMASTER);
+
+	/*
+	 * If the config file specified pgdata, use that as DataDir;
+	 * otherwise use ConfigDir (the original Doption) if set;
+	 * else punt.
+	 *
+	 * Note: SetDataDir will copy and canonicalize its argument,
+	 * so we don't have to.
+	 */
+	if (guc_pgdata)
+		SetDataDir(guc_pgdata);
+	else if (ConfigDir)
+		SetDataDir(ConfigDir);
+	else
+	{
+		write_stderr("%s does not know where to find the database system data.\n"
+					 "This should be specified as \"pgdata\" in \"%s\".\n",
+					 progname, ConfigFileName);
+		return false;
+	}
+
+	/*
+	 * Set ConfigDir as DataDir unless we had another value (which is to say,
+	 * Doption pointed to a directory).  This determines the default location
+	 * of secondary configuration files that will be read later.
+	 */
+	if (!ConfigDir)
+		ConfigDir = DataDir;
+
+	/* If timezone is not set, determine what the OS uses */
+	pg_timezone_initialize();
+
+	return true;
+}
+
+
 /*
  * Reset all options to their saved default values (implements RESET ALL)
  */
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 2eb7baceae49d54e3b11f798be2fa88ae602ebf6..3c689c7eacbad8d4f20df366b54eca7e3aebd60d 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -26,13 +26,17 @@
 
 
 #---------------------------------------------------------------------------
-# CONFIGURATION FILES
+# FILE LOCATIONS
 #---------------------------------------------------------------------------
 
-# 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
+# The default values of these variables are driven from the -D command line
+# switch or PGDATA environment variable, represented here as $PGDATA.
+# pgdata = '$PGDATA'			# use data in another directory
+# hba_conf = '$PGDATA/pg_hba.conf'	# the host-based authentication file
+# ident_conf = '$PGDATA/pg_ident.conf'	# the IDENT configuration file
+
+# If external_pidfile is not explicitly set, no extra pid file is written.
+# external_pidfile = '(none)'		# write an extra pid file
 
 
 #---------------------------------------------------------------------------
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index f6db492dd86f0416e954b584462cd7df02565b15..0639f19da90f036b8606ed3bb444506cc995cf1c 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -7,7 +7,7 @@
  * Copyright (c) 2000-2004, PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
- * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.51 2004/08/29 05:06:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.52 2004/10/08 01:36:36 tgl Exp $
  *--------------------------------------------------------------------
  */
 #ifndef GUC_H
@@ -135,13 +135,12 @@ extern int	log_min_messages;
 extern int	client_min_messages;
 extern int	log_min_duration_statement;
 
-extern char *guc_pgdata;
+extern char *ConfigDir;
+extern char *ConfigFileName;
 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);
@@ -188,6 +187,7 @@ extern const char *GetConfigOption(const char *name);
 extern const char *GetConfigOptionResetString(const char *name);
 extern void ProcessConfigFile(GucContext context);
 extern void InitializeGUCOptions(void);
+extern bool SelectConfigFiles(const char *userDoption, const char *progname);
 extern void ResetAllOptions(void);
 extern void AtEOXact_GUC(bool isCommit, bool isSubXact);
 extern void BeginReportingGUCOptions(void);
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 527fdc88537356c77091115235d01b40b37a11ea..718fac30cbf3425809e4c215c1df11a0980838e1 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -7,7 +7,7 @@
  *
  * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
  *
- *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.16 2004/08/29 05:06:58 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.17 2004/10/08 01:36:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,6 +39,7 @@ union config_var_value
 enum config_group
 {
 	UNGROUPED,
+	FILE_LOCATIONS,
 	CONN_AUTH,
 	CONN_AUTH_SETTINGS,
 	CONN_AUTH_SECURITY,
@@ -69,9 +70,9 @@ enum config_group
 	COMPAT_OPTIONS,
 	COMPAT_OPTIONS_PREVIOUS,
 	COMPAT_OPTIONS_CLIENT,
-	DEVELOPER_OPTIONS,
-	COMPILE_OPTIONS,
-	CUSTOM_OPTIONS
+	PRESET_OPTIONS,
+	CUSTOM_OPTIONS,
+	DEVELOPER_OPTIONS
 };
 
 /*