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 }; /*