database.c 6.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * database.c
4
 *	  miscellaneous initialization support stuff
5
 *
B
Add:  
Bruce Momjian 已提交
6 7
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
8 9 10
 *
 *
 * IDENTIFICATION
11
 *	  $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.39 2000/07/03 20:48:42 petere Exp $
12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

17 18 19 20 21 22
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

B
Bruce Momjian 已提交
23
#include "access/xact.h"
24
#include "catalog/catname.h"
25
#include "catalog/pg_database.h"
B
Bruce Momjian 已提交
26 27 28
#include "miscadmin.h"
#include "utils/syscache.h"

29

30 31 32 33 34 35 36
/*
 * ExpandDatabasePath resolves a proposed database path (obtained from
 * pg_database.datpath) to a full absolute path for further consumption.
 * NULL means an error, which the caller should process. One reason for
 * such an error would be an absolute alternative path when no absolute
 * paths are alllowed.
 */
37 38

char *
39
ExpandDatabasePath(const char *dbpath)
40
{
41
	char		buf[MAXPGPATH];
42
	const char *cp;
43 44
	int			len;

45 46
	AssertArg(dbpath);
	Assert(DataDir);
47

48 49
	if (strlen(dbpath) >= MAXPGPATH)
		return NULL;			/* ain't gonna fit nohow */
50 51 52 53

	/* leading path delimiter? then already absolute path */
	if (*dbpath == SEP_CHAR)
	{
54
#ifdef ALLOW_ABSOLUTE_DBPATHS
55
		cp = strrchr(dbpath, SEP_CHAR);
56 57
		len = cp - dbpath;
		strncpy(buf, dbpath, len);
58
		snprintf(&buf[len], MAXPGPATH - len, "%cbase%c%s",
59
				 SEP_CHAR, SEP_CHAR, (cp + 1));
60 61 62
#else
		return NULL;
#endif
63 64
	}
	/* path delimiter somewhere? then has leading environment variable */
65
	else if ((cp = strchr(dbpath, SEP_CHAR)) != NULL)
66
	{
67
		const char *envvar;
68

69 70 71 72 73
		len = cp - dbpath;
		strncpy(buf, dbpath, len);
		buf[len] = '\0';
		envvar = getenv(buf);
		if (envvar == NULL)
74
			return NULL;
75

76 77
		snprintf(buf, sizeof(buf), "%s%cbase%c%s",
				 envvar, SEP_CHAR, SEP_CHAR, (cp + 1));
78 79
	}
	else
80 81 82 83 84
	{
		/* no path delimiter? then add the default path prefix */
		snprintf(buf, sizeof(buf), "%s%cbase%c%s",
				 DataDir, SEP_CHAR, SEP_CHAR, dbpath);
	}
85

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
	/*
	 * check for illegal characters in dbpath these should really throw an
	 * error, shouldn't they? or else all callers need to test for NULL
	 */
	for (cp = buf; *cp; cp++)
	{

		/*
		 * The following characters will not be allowed anywhere in the
		 * database path. (Do not include the slash  or '.' here.)
		 */
		char		illegal_dbpath_chars[] =
		"\001\002\003\004\005\006\007\010"
		"\011\012\013\014\015\016\017\020"
		"\021\022\023\024\025\026\027\030"
		"\031\032\033\034\035\036\037"
		"'`";

		const char *cx;

		for (cx = illegal_dbpath_chars; *cx; cx++)
			if (*cp == *cx)
				return NULL;
		/* don't allow access to parent dirs */
		if (strncmp(cp, "/../", 4) == 0)
			return NULL;
	}
113

114
	return pstrdup(buf);
115
}	/* ExpandDatabasePath() */
116 117


118

119 120 121 122 123 124 125 126 127
/* --------------------------------
 *	GetRawDatabaseInfo() -- Find the OID and path of the database.
 *
 *		The database's oid forms half of the unique key for the system
 *		caches and lock tables.  We therefore want it initialized before
 *		we open any relations, since opening relations puts things in the
 *		cache.	To get around this problem, this code opens and scans the
 *		pg_database relation by hand.
 *
128 129 130
 *		This code knows way more than it should about the layout of
 *		tuples on disk, but there seems to be no help for that.
 *		We're pulling ourselves up by the bootstraps here...
131 132 133
 * --------------------------------
 */
void
134
GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
135 136 137 138 139
{
	int			dbfd;
	int			nbytes;
	int			max,
				i;
B
Bruce Momjian 已提交
140
	HeapTupleData tup;
141 142 143 144 145
	Page		pg;
	PageHeader	ph;
	char	   *dbfname;
	Form_pg_database tup_db;

146 147
	dbfname = (char *) palloc(strlen(DataDir) + 8 + strlen(DatabaseRelationName) + 2);
	sprintf(dbfname, "%s/global/%s", DataDir, DatabaseRelationName);
148

149
	if ((dbfd = open(dbfname, O_RDONLY | PG_BINARY, 0)) < 0)
150
		elog(FATAL, "cannot open %s: %s", dbfname, strerror(errno));
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

	pfree(dbfname);

	/* ----------------
	 *	read and examine every page in pg_database
	 *
	 *	Raw I/O! Read those tuples the hard way! Yow!
	 *
	 *	Why don't we use the access methods or move this code
	 *	someplace else?  This is really pg_database schema dependent
	 *	code.  Perhaps it should go in lib/catalog/pg_database?
	 *	-cim 10/3/90
	 *
	 *	mao replies 4 apr 91:  yeah, maybe this should be moved to
	 *	lib/catalog.  however, we CANNOT use the access methods since
	 *	those use the buffer cache, which uses the relation cache, which
	 *	requires that the dbid be set, which is what we're trying to do
	 *	here.
	 * ----------------
	 */
	pg = (Page) palloc(BLCKSZ);
	ph = (PageHeader) pg;

	while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ)
	{
		max = PageGetMaxOffsetNumber(pg);

		/* look at each tuple on the page */
		for (i = 0; i <= max; i++)
		{
			int			offset;

			/* if it's a freed tuple, ignore it */
			if (!(ph->pd_linp[i].lp_flags & LP_USED))
				continue;

			/* get a pointer to the tuple itself */
			offset = (int) ph->pd_linp[i].lp_off;
189
			tup.t_datamcxt = NULL;
190
			tup.t_data = (HeapTupleHeader) (((char *) pg) + offset);
191 192 193 194 195 196

			/*
			 * if the tuple has been deleted (the database was destroyed),
			 * skip this tuple.  XXX warning, will robinson:  violation of
			 * transaction semantics happens right here.  we should check
			 * to be sure that the xact that deleted this tuple actually
197 198 199 200
			 * committed.  Only way to do that at init time is to paw over
			 * the log relation by hand, too.  Instead we take the
			 * conservative assumption that if someone tried to delete it,
			 * it's gone.  The other side of the coin is that we might
201 202
			 * accept a tuple that was stored and never committed.	All in
			 * all, this code is pretty shaky.	We will cross-check our
203
			 * result in ReverifyMyDatabase() in postinit.c.
204
			 *
205 206 207
			 * NOTE: if a bogus tuple in pg_database prevents connection to a
			 * valid database, a fix is to connect to another database and
			 * do "select * from pg_database".	That should cause
208 209 210
			 * committed and dead tuples to be marked with correct states.
			 *
			 * XXX wouldn't it be better to let new backends read the
211 212
			 * database OID from a flat file, handled the same way we
			 * handle the password relation?
213
			 */
214
			if (TransactionIdIsValid((TransactionId) tup.t_data->t_xmax))
215 216 217
				continue;

			/*
218
			 * Okay, see if this is the one we want.
219
			 */
220
			tup_db = (Form_pg_database) GETSTRUCT(&tup);
221

222
			if (strcmp(name, NameStr(tup_db->datname)) == 0)
223
			{
224
				/* Found it; extract the OID and the database path. */
225
				*db_id = tup.t_data->t_oid;
226
				strncpy(path, VARDATA(&(tup_db->datpath)),
227 228
						(VARSIZE(&(tup_db->datpath)) - VARHDRSZ));
				*(path + VARSIZE(&(tup_db->datpath)) - VARHDRSZ) = '\0';
229 230 231 232 233 234 235 236
				goto done;
			}
		}
	}

done:
	close(dbfd);
	pfree(pg);
237
}	/* GetRawDatabaseInfo() */