miscinit.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 947 行 · 第 1/2 页

C
947
字号
/*------------------------------------------------------------------------- * * miscinit.c *	  miscellaneous initialization support stuff * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.116 2003/09/26 15:27:37 petere Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <sys/param.h>#include <signal.h>#include <sys/file.h>#include <sys/stat.h>#include <sys/time.h>#include <fcntl.h>#include <unistd.h>#include <grp.h>#include <pwd.h>#include <errno.h>#include <netinet/in.h>#include <arpa/inet.h>#ifdef HAVE_UTIME_H#include <utime.h>#endif#include "catalog/catname.h"#include "catalog/pg_shadow.h"#include "libpq/libpq-be.h"#include "miscadmin.h"#include "storage/ipc.h"#include "storage/pg_shmem.h"#include "utils/builtins.h"#include "utils/guc.h"#include "utils/lsyscache.h"#include "utils/syscache.h"ProcessingMode Mode = InitProcessing;/* Note: we rely on these to initialize as zeroes */static char directoryLockFile[MAXPGPATH];static char socketLockFile[MAXPGPATH];/* ---------------------------------------------------------------- *		ignoring system indexes support stuff * * NOTE: "ignoring system indexes" means we do not use the system indexes * for lookups (either in hardwired catalog accesses or in planner-generated * plans).  We do, however, still update the indexes when a catalog * modification is made. * ---------------------------------------------------------------- */static bool isIgnoringSystemIndexes = false;/* * IsIgnoringSystemIndexes *		True if ignoring system indexes. */boolIsIgnoringSystemIndexes(void){	return isIgnoringSystemIndexes;}/* * IgnoreSystemIndexes *		Set true or false whether PostgreSQL ignores system indexes. */voidIgnoreSystemIndexes(bool mode){	isIgnoringSystemIndexes = mode;}/* ---------------------------------------------------------------- *		system index reindexing support * * When we are busy reindexing a system index, this code provides support * for preventing catalog lookups from using that index. * ---------------------------------------------------------------- */static Oid	currentlyReindexedHeap = InvalidOid;static Oid	currentlyReindexedIndex = InvalidOid;/* * ReindexIsProcessingHeap *		True if heap specified by OID is currently being reindexed. */boolReindexIsProcessingHeap(Oid heapOid){	return heapOid == currentlyReindexedHeap;}/* * ReindexIsProcessingIndex *		True if index specified by OID is currently being reindexed. */boolReindexIsProcessingIndex(Oid indexOid){	return indexOid == currentlyReindexedIndex;}/* * SetReindexProcessing *		Set flag that specified heap/index are being reindexed. *		Pass InvalidOid to indicate that reindexing is not active. */voidSetReindexProcessing(Oid heapOid, Oid indexOid){	/* Args should be both, or neither, InvalidOid */	Assert((heapOid == InvalidOid) == (indexOid == InvalidOid));	/* Reindexing is not re-entrant. */	Assert(indexOid == InvalidOid || currentlyReindexedIndex == InvalidOid);	currentlyReindexedHeap = heapOid;	currentlyReindexedIndex = indexOid;}/* ---------------------------------------------------------------- *				database path / name support stuff * ---------------------------------------------------------------- */voidSetDatabasePath(const char *path){	if (DatabasePath)	{		free(DatabasePath);		DatabasePath = NULL;	}	/* use strdup since this is done before memory contexts are set up */	if (path)	{		DatabasePath = strdup(path);		AssertState(DatabasePath);	}}/* * Set data directory, but make sure it's an absolute path.  Use this, * never set DataDir directly. */voidSetDataDir(const char *dir){	char	   *new;	int			newlen;	AssertArg(dir);	/* If presented path is relative, convert to absolute */	if (!is_absolute_path(dir))	{		char	   *buf;		size_t		buflen;		buflen = MAXPGPATH;		for (;;)		{			buf = malloc(buflen);			if (!buf)				ereport(FATAL,						(errcode(ERRCODE_OUT_OF_MEMORY),						 errmsg("out of memory")));			if (getcwd(buf, buflen))				break;			else if (errno == ERANGE)			{				free(buf);				buflen *= 2;				continue;			}			else			{				free(buf);				elog(FATAL, "could not get current working directory: %m");			}		}		new = malloc(strlen(buf) + 1 + strlen(dir) + 1);		if (!new)			ereport(FATAL,					(errcode(ERRCODE_OUT_OF_MEMORY),					 errmsg("out of memory")));		sprintf(new, "%s/%s", buf, dir);		free(buf);	}	else	{		new = strdup(dir);		if (!new)			ereport(FATAL,					(errcode(ERRCODE_OUT_OF_MEMORY),					 errmsg("out of memory")));	}	/*	 * Strip any trailing slash.  Not strictly necessary, but avoids	 * generating funny-looking paths to individual files.	 */	newlen = strlen(new);	if (newlen > 1 && new[newlen - 1] == '/'#ifdef WIN32		|| new[newlen - 1] == '\\'#endif		)		new[newlen - 1] = '\0';	if (DataDir)		free(DataDir);	DataDir = new;}/* ---------------------------------------------------------------- *	User ID things * * The authenticated user is determined at connection start and never * changes.  The session user can be changed only by SET SESSION * AUTHORIZATION.  The current user may change when "setuid" functions * are implemented.  Conceptually there is a stack, whose bottom * is the session user.  You are yourself responsible to save and * restore the current user id if you need to change it. * ---------------------------------------------------------------- */static AclId AuthenticatedUserId = 0;static AclId SessionUserId = 0;static AclId CurrentUserId = 0;static bool AuthenticatedUserIsSuperuser = false;/* * This function is relevant for all privilege checks. */AclIdGetUserId(void){	AssertState(AclIdIsValid(CurrentUserId));	return CurrentUserId;}voidSetUserId(AclId newid){	AssertArg(AclIdIsValid(newid));	CurrentUserId = newid;}/* * This value is only relevant for informational purposes. */AclIdGetSessionUserId(void){	AssertState(AclIdIsValid(SessionUserId));	return SessionUserId;}voidSetSessionUserId(AclId newid){	AssertArg(AclIdIsValid(newid));	SessionUserId = newid;	/* Current user defaults to session user. */	if (!AclIdIsValid(CurrentUserId))		CurrentUserId = newid;}voidInitializeSessionUserId(const char *username){	HeapTuple	userTup;	Datum		datum;	bool		isnull;	AclId		usesysid;	/*	 * Don't do scans if we're bootstrapping, none of the system catalogs	 * exist yet, and they should be owned by postgres anyway.	 */	AssertState(!IsBootstrapProcessingMode());	/* call only once */	AssertState(!OidIsValid(AuthenticatedUserId));	userTup = SearchSysCache(SHADOWNAME,							 PointerGetDatum(username),							 0, 0, 0);	if (!HeapTupleIsValid(userTup))		ereport(FATAL,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("user \"%s\" does not exist", username)));	usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;	AuthenticatedUserId = usesysid;	AuthenticatedUserIsSuperuser = ((Form_pg_shadow) GETSTRUCT(userTup))->usesuper;	SetSessionUserId(usesysid); /* sets CurrentUserId too */	/* Record username and superuser status as GUC settings too */	SetConfigOption("session_authorization", username,					PGC_BACKEND, PGC_S_OVERRIDE);	SetConfigOption("is_superuser",					AuthenticatedUserIsSuperuser ? "on" : "off",					PGC_INTERNAL, PGC_S_OVERRIDE);	/*	 * Set up user-specific configuration variables.  This is a good place	 * to do it so we don't have to read pg_shadow twice during session	 * startup.	 */	datum = SysCacheGetAttr(SHADOWNAME, userTup,							Anum_pg_shadow_useconfig, &isnull);	if (!isnull)	{		ArrayType  *a = DatumGetArrayTypeP(datum);		ProcessGUCArray(a, PGC_S_USER);	}	ReleaseSysCache(userTup);}voidInitializeSessionUserIdStandalone(void){	/* This function should only be called in a single-user backend. */	AssertState(!IsUnderPostmaster);	/* call only once */	AssertState(!OidIsValid(AuthenticatedUserId));	AuthenticatedUserId = BOOTSTRAP_USESYSID;	AuthenticatedUserIsSuperuser = true;	SetSessionUserId(BOOTSTRAP_USESYSID);}/* * Change session auth ID while running * * Only a superuser may set auth ID to something other than himself.  Note * that in case of multiple SETs in a single session, the original userid's * superuserness is what matters.  But we set the GUC variable is_superuser * to indicate whether the *current* session userid is a superuser. */voidSetSessionAuthorization(AclId userid, bool is_superuser){	/* Must have authenticated already, else can't make permission check */	AssertState(AclIdIsValid(AuthenticatedUserId));	if (userid != AuthenticatedUserId &&		!AuthenticatedUserIsSuperuser)		ereport(ERROR,				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),			  errmsg("permission denied to set session authorization")));	SetSessionUserId(userid);	SetUserId(userid);	SetConfigOption("is_superuser",					is_superuser ? "on" : "off",					PGC_INTERNAL, PGC_S_OVERRIDE);}/* * Get user name from user id */char *GetUserNameFromId(AclId userid){	HeapTuple	tuple;	char	   *result;	tuple = SearchSysCache(SHADOWSYSID,						   ObjectIdGetDatum(userid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("invalid user ID: %d", userid)));	result = pstrdup(NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename));	ReleaseSysCache(tuple);	return result;}/*------------------------------------------------------------------------- *				Interlock-file support * * These routines are used to create both a data-directory lockfile * ($DATADIR/postmaster.pid) and a Unix-socket-file lockfile ($SOCKFILE.lock). * Both kinds of files contain the same info: * *		Owning process' PID *		Data directory path * * By convention, the owning process' PID is negated if it is a standalone * backend rather than a postmaster.  This is just for informational purposes. * The path is also just for informational purposes (so that a socket lockfile * can be more easily traced to the associated postmaster). * * A data-directory lockfile can optionally contain a third line, containing * the key and ID for the shared memory block used by this postmaster. * * On successful lockfile creation, a proc_exit callback to remove the * lockfile is automatically created. *------------------------------------------------------------------------- *//* * proc_exit callback to remove a lockfile. */static voidUnlinkLockFile(int status, Datum filename){	char	   *fname = (char *) DatumGetPointer(filename);	if (fname != NULL)	{		if (unlink(fname) != 0)		{			/* Should we complain if the unlink fails? */		}		free(fname);	}}/* * Create a lockfile. * * filename is the name of the lockfile to create. * amPostmaster is used to determine how to encode the output PID. * isDDLock and refName are used to determine what error message to produce. */static voidCreateLockFile(const char *filename, bool amPostmaster,			   bool isDDLock, const char *refName){	int			fd;	char		buffer[MAXPGPATH + 100];	int			ntries;	int			len;	int			encoded_pid;	pid_t		other_pid;	pid_t		my_pid = getpid();	/*

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?