Commit 33043417 authored by Peter Eisentraut's avatar Peter Eisentraut

Reimplement alternative database locations with symlinks. No changes in

user interface.
parent 218f357d
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.63 2000/10/28 16:20:54 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.64 2000/11/08 16:59:49 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,8 +17,6 @@ ...@@ -17,8 +17,6 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
...@@ -37,12 +35,10 @@ ...@@ -37,12 +35,10 @@
/* non-export function prototypes */ /* non-export function prototypes */
static bool static bool get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb);
get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb); static bool get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP);
static char * resolve_alt_dbpath(const char * dbpath, Oid dboid);
static bool static bool remove_dbdirs(const char * real_loc, const char * altloc);
get_db_info(const char *name, char *dbpath, Oid *dbIdP, int4 *ownerIdP);
/* /*
* CREATE DATABASE * CREATE DATABASE
...@@ -52,8 +48,8 @@ void ...@@ -52,8 +48,8 @@ void
createdb(const char *dbname, const char *dbpath, int encoding) createdb(const char *dbname, const char *dbpath, int encoding)
{ {
char buf[2 * MAXPGPATH + 100]; char buf[2 * MAXPGPATH + 100];
char *loc; char *altloc;
char locbuf[512]; char *real_loc;
int ret; int ret;
bool use_super, bool use_super,
use_createdb; use_createdb;
...@@ -77,24 +73,6 @@ createdb(const char *dbname, const char *dbpath, int encoding) ...@@ -77,24 +73,6 @@ createdb(const char *dbname, const char *dbpath, int encoding)
if (IsTransactionBlock()) if (IsTransactionBlock())
elog(ERROR, "CREATE DATABASE: may not be called in a transaction block"); elog(ERROR, "CREATE DATABASE: may not be called in a transaction block");
#ifdef OLD_FILE_NAMING
/* Generate directory name for the new database */
if (dbpath == NULL || strcmp(dbpath, dbname) == 0)
strcpy(locbuf, dbname);
else
snprintf(locbuf, sizeof(locbuf), "%s/%s", dbpath, dbname);
loc = ExpandDatabasePath(locbuf);
if (loc == NULL)
elog(ERROR,
"The database path '%s' is invalid. "
"This may be due to a character that is not allowed or because the chosen "
"path isn't permitted for databases", dbpath);
#else
locbuf[0] = 0; /* Avoid junk in strings */
#endif
/* /*
* Insert a new tuple into pg_database * Insert a new tuple into pg_database
*/ */
...@@ -108,13 +86,15 @@ createdb(const char *dbname, const char *dbpath, int encoding) ...@@ -108,13 +86,15 @@ createdb(const char *dbname, const char *dbpath, int encoding)
dboid = newoid(); dboid = newoid();
/* Form tuple */ /* Form tuple */
new_record[Anum_pg_database_datname - 1] = DirectFunctionCall1(namein, new_record[Anum_pg_database_datname - 1] =
CStringGetDatum(dbname)); DirectFunctionCall1(namein, CStringGetDatum(dbname));
new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(GetUserId()); new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(GetUserId());
new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding); new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(dboid); /* Save current OID val */ /* Save current OID val */
new_record[Anum_pg_database_datpath - 1] = DirectFunctionCall1(textin, new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(dboid);
CStringGetDatum(locbuf)); /* no nulls here, GetRawDatabaseInfo doesn't like them */
new_record[Anum_pg_database_datpath - 1] =
DirectFunctionCall1(textin, CStringGetDatum(dbpath ? dbpath : ""));
tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls); tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);
...@@ -126,9 +106,12 @@ createdb(const char *dbname, const char *dbpath, int encoding) ...@@ -126,9 +106,12 @@ createdb(const char *dbname, const char *dbpath, int encoding)
*/ */
heap_insert(pg_database_rel, tuple); heap_insert(pg_database_rel, tuple);
#ifndef OLD_FILE_NAMING real_loc = GetDatabasePath(tuple->t_data->t_oid);
loc = GetDatabasePath(tuple->t_data->t_oid); altloc = resolve_alt_dbpath(dbpath, tuple->t_data->t_oid);
#endif
if (strchr(real_loc, '\'') && strchr(altloc, '\''))
elog(ERROR, "database path may not contain single quotes");
/* ... otherwise we'd be open to shell exploits below */
/* /*
* Update indexes (there aren't any currently) * Update indexes (there aren't any currently)
...@@ -156,41 +139,28 @@ createdb(const char *dbname, const char *dbpath, int encoding) ...@@ -156,41 +139,28 @@ createdb(const char *dbname, const char *dbpath, int encoding)
/* Copy the template database to the new location */ /* Copy the template database to the new location */
if (mkdir(loc, S_IRWXU) != 0) if (mkdir((altloc ? altloc : real_loc), S_IRWXU) != 0)
elog(ERROR, "CREATE DATABASE: unable to create database directory '%s': %s", loc, strerror(errno)); elog(ERROR, "CREATE DATABASE: unable to create database directory '%s': %s",
(altloc ? altloc : real_loc), strerror(errno));
#ifdef OLD_FILE_NAMING if (altloc)
snprintf(buf, sizeof(buf), "cp %s%cbase%ctemplate1%c* '%s'",
DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, loc);
#else
{ {
char *tmpl = GetDatabasePath(TemplateDbOid); if (symlink(altloc, real_loc) != 0)
elog(ERROR, "CREATE DATABASE: could not link %s to %s: %s",
snprintf(buf, sizeof(buf), "cp %s%c* '%s'", real_loc, altloc, strerror(errno));
tmpl, SEP_CHAR, loc);
pfree(tmpl);
} }
#endif
snprintf(buf, sizeof(buf), "cp '%s'/* '%s'",
GetDatabasePath(TemplateDbOid), real_loc);
ret = system(buf); ret = system(buf);
/* Some versions of SunOS seem to return ECHILD after a system() call */ /* Some versions of SunOS seem to return ECHILD after a system() call */
#if defined(sun)
if (ret != 0 && errno != ECHILD) if (ret != 0 && errno != ECHILD)
#else
if (ret != 0)
#endif
{ {
/* Failed, so try to clean up the created directory ... */ if (remove_dbdirs(real_loc, altloc))
snprintf(buf, sizeof(buf), "rm -rf '%s'", loc);
ret = system(buf);
#if defined(sun)
if (ret == 0 || errno == ECHILD)
#else
if (ret == 0)
#endif
elog(ERROR, "CREATE DATABASE: could not initialize database directory"); elog(ERROR, "CREATE DATABASE: could not initialize database directory");
else else
elog(ERROR, "CREATE DATABASE: Could not initialize database directory. Delete failed as well"); elog(ERROR, "CREATE DATABASE: could not initialize database directory; delete failed as well");
} }
#ifdef XLOG #ifdef XLOG
...@@ -210,9 +180,9 @@ dropdb(const char *dbname) ...@@ -210,9 +180,9 @@ dropdb(const char *dbname)
int4 db_owner; int4 db_owner;
bool use_super; bool use_super;
Oid db_id; Oid db_id;
char *path, char *altloc;
dbpath[MAXPGPATH], char *real_loc;
buf[MAXPGPATH + 100]; char dbpath[MAXPGPATH];
Relation pgdbrel; Relation pgdbrel;
HeapScanDesc pgdbscan; HeapScanDesc pgdbscan;
ScanKeyData key; ScanKeyData key;
...@@ -221,33 +191,25 @@ dropdb(const char *dbname) ...@@ -221,33 +191,25 @@ dropdb(const char *dbname)
AssertArg(dbname); AssertArg(dbname);
if (strcmp(dbname, "template1") == 0) if (strcmp(dbname, "template1") == 0)
elog(ERROR, "DROP DATABASE: May not be executed on the template1 database"); elog(ERROR, "DROP DATABASE: may not be executed on the template1 database");
if (strcmp(dbname, DatabaseName) == 0) if (strcmp(dbname, DatabaseName) == 0)
elog(ERROR, "DROP DATABASE: Cannot be executed on the currently open database"); elog(ERROR, "DROP DATABASE: cannot be executed on the currently open database");
if (IsTransactionBlock()) if (IsTransactionBlock())
elog(ERROR, "DROP DATABASE: May not be called in a transaction block"); elog(ERROR, "DROP DATABASE: may not be called in a transaction block");
if (!get_user_info(GetUserId(), &use_super, NULL)) if (!get_user_info(GetUserId(), &use_super, NULL))
elog(ERROR, "Current user name is invalid"); elog(ERROR, "current user name is invalid");
if (!get_db_info(dbname, dbpath, &db_id, &db_owner)) if (!get_db_info(dbname, dbpath, &db_id, &db_owner))
elog(ERROR, "DROP DATABASE: Database \"%s\" does not exist", dbname); elog(ERROR, "DROP DATABASE: database \"%s\" does not exist", dbname);
if (GetUserId() != db_owner && !use_super) if (GetUserId() != db_owner && !use_super)
elog(ERROR, "DROP DATABASE: Permission denied"); elog(ERROR, "DROP DATABASE: permission denied");
#ifdef OLD_FILE_NAMING real_loc = GetDatabasePath(db_id);
path = ExpandDatabasePath(dbpath); altloc = resolve_alt_dbpath(dbpath, db_id);
if (path == NULL)
elog(ERROR,
"The database path '%s' is invalid. "
"This may be due to a character that is not allowed or because the chosen "
"path isn't permitted for databases", path);
#else
path = GetDatabasePath(db_id);
#endif
/* /*
* Obtain exclusive lock on pg_database. We need this to ensure that * Obtain exclusive lock on pg_database. We need this to ensure that
...@@ -266,7 +228,7 @@ dropdb(const char *dbname) ...@@ -266,7 +228,7 @@ dropdb(const char *dbname)
if (DatabaseHasActiveBackends(db_id)) if (DatabaseHasActiveBackends(db_id))
{ {
heap_close(pgdbrel, AccessExclusiveLock); heap_close(pgdbrel, AccessExclusiveLock);
elog(ERROR, "DROP DATABASE: Database \"%s\" is being accessed by other users", dbname); elog(ERROR, "DROP DATABASE: database \"%s\" is being accessed by other users", dbname);
} }
/* /*
...@@ -320,13 +282,7 @@ dropdb(const char *dbname) ...@@ -320,13 +282,7 @@ dropdb(const char *dbname)
/* /*
* Remove the database's subdirectory and everything in it. * Remove the database's subdirectory and everything in it.
*/ */
snprintf(buf, sizeof(buf), "rm -rf '%s'", path); remove_dbdirs(real_loc, altloc);
#if defined(sun)
if (system(buf) != 0 && errno != ECHILD)
#else
if (system(buf) != 0)
#endif
elog(NOTICE, "DROP DATABASE: The database directory '%s' could not be removed", path);
} }
...@@ -426,3 +382,66 @@ get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb) ...@@ -426,3 +382,66 @@ get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb)
return true; return true;
} }
static char *
resolve_alt_dbpath(const char * dbpath, Oid dboid)
{
char * prefix;
char * ret;
size_t len;
if (dbpath == NULL || dbpath[0] == '\0')
return NULL;
if (strchr(dbpath, '/'))
{
#ifdef ALLOW_ABSOLUTE_DBPATHS
prefix = dbpath;
#else
elog(ERROR, "Absolute paths are not allowed as database locations");
#endif
}
else
{
/* must be environment variable */
char * var = getenv(dbpath);
if (!var)
elog(ERROR, "environment variable %s not set", dbpath);
if (var[0] != '/')
elog(ERROR, "environment variable %s must be absolute path", dbpath);
prefix = var;
}
len = strlen(prefix) + 6 + sizeof(Oid) * 8 + 1;
ret = palloc(len);
snprintf(ret, len, "%s/base/%u", prefix, dboid);
return ret;
}
static bool
remove_dbdirs(const char * real_loc, const char * altloc)
{
char buf[MAXPGPATH + 100];
bool success = true;
if (altloc)
/* remove symlink */
if (unlink(real_loc) != 0)
{
elog(NOTICE, "could not remove '%s': %s", real_loc, strerror(errno));
success = false;
}
snprintf(buf, sizeof(buf), "rm -rf '%s'", altloc ? altloc : real_loc);
if (system(buf) != 0 && errno != ECHILD)
{
elog(NOTICE, "database directory '%s' could not be removed",
altloc ? altloc : real_loc);
success = false;
}
return success;
}
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.55 2000/11/06 15:58:46 thomas Exp $ * $Id: catversion.h,v 1.56 2000/11/08 16:59:50 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200011060 #define CATALOG_VERSION_NO 200011080
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_database.h,v 1.13 2000/10/22 18:29:58 tgl Exp $ * $Id: pg_database.h,v 1.14 2000/11/08 16:59:50 petere Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -58,7 +58,7 @@ typedef FormData_pg_database *Form_pg_database; ...@@ -58,7 +58,7 @@ typedef FormData_pg_database *Form_pg_database;
#define Anum_pg_database_datlastsysoid 4 #define Anum_pg_database_datlastsysoid 4
#define Anum_pg_database_datpath 5 #define Anum_pg_database_datpath 5
DATA(insert OID = 1 ( template1 PGUID ENCODING 0 template1 )); DATA(insert OID = 1 ( template1 PGUID ENCODING 0 "" ));
DESCR(""); DESCR("");
#define TemplateDbOid 1 #define TemplateDbOid 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