Commit d90984f4 authored by Tom Lane's avatar Tom Lane

Install some simple defenses in postmaster startup to help ensure a useful

error message if the installation directory layout is messed up (or at least,
something more useful than the behavior exhibited in bug #4787).  During
postmaster startup, check that get_pkglib_path resolves as a readable
directory; and if ParseTzFile() fails to open the expected timezone
abbreviation file, check the possibility that the directory is missing rather
than just the specified file.  In case of either failure, issue a hint
suggesting that the installation is broken.  These two checks cover the lib/
and share/ trees of a full installation, which should take care of most
scenarios where a sysadmin decides to get cute.
parent a16e007c
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.577 2009/04/05 04:19:58 tgl Exp $ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.578 2009/05/02 22:02:37 tgl Exp $
* *
* NOTES * NOTES
* *
...@@ -315,6 +315,7 @@ extern int optreset; /* might not be declared by system headers */ ...@@ -315,6 +315,7 @@ extern int optreset; /* might not be declared by system headers */
/* /*
* postmaster.c - function prototypes * postmaster.c - function prototypes
*/ */
static void getInstallationPaths(const char *argv0);
static void checkDataDir(void); static void checkDataDir(void);
#ifdef USE_BONJOUR #ifdef USE_BONJOUR
...@@ -493,11 +494,8 @@ PostmasterMain(int argc, char *argv[]) ...@@ -493,11 +494,8 @@ PostmasterMain(int argc, char *argv[])
ALLOCSET_DEFAULT_MAXSIZE); ALLOCSET_DEFAULT_MAXSIZE);
MemoryContextSwitchTo(PostmasterContext); MemoryContextSwitchTo(PostmasterContext);
if (find_my_exec(argv[0], my_exec_path) < 0) /* Initialize paths to installation files */
elog(FATAL, "%s: could not locate my own executable path", getInstallationPaths(argv[0]);
argv[0]);
get_pkglib_path(my_exec_path, pkglib_path);
/* /*
* Options setup * Options setup
...@@ -690,15 +688,6 @@ PostmasterMain(int argc, char *argv[]) ...@@ -690,15 +688,6 @@ PostmasterMain(int argc, char *argv[])
ExitPostmaster(1); ExitPostmaster(1);
} }
#ifdef EXEC_BACKEND
/* Locate executable backend before we change working directory */
if (find_other_exec(argv[0], "postgres", PG_BACKEND_VERSIONSTR,
postgres_exec_path) < 0)
ereport(FATAL,
(errmsg("%s: could not locate matching postgres executable",
progname)));
#endif
/* /*
* Locate the proper configuration files and data directory, and read * Locate the proper configuration files and data directory, and read
* postgresql.conf for the first time. * postgresql.conf for the first time.
...@@ -1062,6 +1051,58 @@ PostmasterMain(int argc, char *argv[]) ...@@ -1062,6 +1051,58 @@ PostmasterMain(int argc, char *argv[])
} }
/*
* Compute and check the directory paths to files that are part of the
* installation (as deduced from the postgres executable's own location)
*/
static void
getInstallationPaths(const char *argv0)
{
DIR *pdir;
/* Locate the postgres executable itself */
if (find_my_exec(argv0, my_exec_path) < 0)
elog(FATAL, "%s: could not locate my own executable path", argv0);
#ifdef EXEC_BACKEND
/* Locate executable backend before we change working directory */
if (find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
postgres_exec_path) < 0)
ereport(FATAL,
(errmsg("%s: could not locate matching postgres executable",
argv0)));
#endif
/*
* Locate the pkglib directory --- this has to be set early in case we try
* to load any modules from it in response to postgresql.conf entries.
*/
get_pkglib_path(my_exec_path, pkglib_path);
/*
* Verify that there's a readable directory there; otherwise the
* Postgres installation is incomplete or corrupt. (A typical cause
* of this failure is that the postgres executable has been moved or
* hardlinked to some directory that's not a sibling of the installation
* lib/ directory.)
*/
pdir = AllocateDir(pkglib_path);
if (pdir == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m",
pkglib_path),
errhint("This may indicate an incomplete PostgreSQL installation, or that the file \"%s\" has been moved away from its proper location.",
my_exec_path)));
FreeDir(pdir);
/*
* XXX is it worth similarly checking the share/ directory? If the
* lib/ directory is there, then share/ probably is too.
*/
}
/* /*
* Validate the proposed data directory * Validate the proposed data directory
*/ */
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/tzparser.c,v 1.7 2009/01/01 17:23:53 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/misc/tzparser.c,v 1.8 2009/05/02 22:02:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -326,12 +326,41 @@ ParseTzFile(const char *filename, int depth, ...@@ -326,12 +326,41 @@ ParseTzFile(const char *filename, int depth,
tzFile = AllocateFile(file_path, "r"); tzFile = AllocateFile(file_path, "r");
if (!tzFile) if (!tzFile)
{ {
/* at level 0, if file doesn't exist, guc.c's complaint is enough */ /*
* Check to see if the problem is not the filename but the directory.
* This is worth troubling over because if the installation share/
* directory is missing or unreadable, this is likely to be the first
* place we notice a problem during postmaster startup.
*/
int save_errno = errno;
DIR *tzdir;
snprintf(file_path, sizeof(file_path), "%s/timezonesets",
share_path);
tzdir = AllocateDir(file_path);
if (tzdir == NULL)
{
ereport(tz_elevel,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m",
file_path),
errhint("This may indicate an incomplete PostgreSQL installation, or that the file \"%s\" has been moved away from its proper location.",
my_exec_path)));
return -1;
}
FreeDir(tzdir);
errno = save_errno;
/*
* otherwise, if file doesn't exist and it's level 0, guc.c's
* complaint is enough
*/
if (errno != ENOENT || depth > 0) if (errno != ENOENT || depth > 0)
ereport(tz_elevel, ereport(tz_elevel,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read time zone file \"%s\": %m", errmsg("could not read time zone file \"%s\": %m",
filename))); filename)));
return -1; return -1;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment