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 + -
显示快捷键?