/* * Any Postgres server process begins execution here. */ int main(int argc, char *argv[]) { bool do_check_root = true; progname = get_progname(argv[0]); /* * Platform-specific startup hacks */ startup_hacks(progname); /* * Remember the physical location of the initially given argv[] array for * possible use by ps display. On some platforms, the argv[] storage must * be overwritten in order to set the process title for ps. In such cases * save_ps_display_args makes and returns a new copy of the argv[] array. * * save_ps_display_args may also move the environment strings to make * extra room. Therefore this should be done as early as possible during * startup, to avoid entanglements with code that might save a getenv() * result pointer. */ argv = save_ps_display_args(argc, argv); /* * If supported on the current platform, set up a handler to be called if * the backend/postmaster crashes with a fatal signal or exception. */ #if defined(WIN32) && defined(HAVE_MINIDUMP_TYPE) pgwin32_install_crashdump_handler(); #endif /* * Fire up essential subsystems: error and memory management * * Code after this point is allowed to use elog/ereport, though * localization of messages may not work right away, and messages won't go * anywhere but stderr until GUC settings get loaded. */ MemoryContextInit(); /* * Set up locale information from environment. Note that LC_CTYPE and * LC_COLLATE will be overridden later from pg_control if we are in an * already-initialized database. We set them here so that they will be * available to fill pg_control during initdb. LC_MESSAGES will get set * later during GUC option processing, but we set it here to allow startup * error messages to be localized. */ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("postgres")); #ifdef WIN32 /* * Windows uses codepages rather than the environment, so we work around * that by querying the environment explicitly first for LC_COLLATE and * LC_CTYPE. We have to do this because initdb passes those values in the * environment. If there is nothing there we fall back on the codepage. */ { char *env_locale; if ((env_locale = getenv("LC_COLLATE")) != NULL) init_locale("LC_COLLATE", LC_COLLATE, env_locale); else init_locale("LC_COLLATE", LC_COLLATE, ""); if ((env_locale = getenv("LC_CTYPE")) != NULL) init_locale("LC_CTYPE", LC_CTYPE, env_locale); else init_locale("LC_CTYPE", LC_CTYPE, ""); } #else init_locale("LC_COLLATE", LC_COLLATE, ""); init_locale("LC_CTYPE", LC_CTYPE, ""); #endif #ifdef LC_MESSAGES init_locale("LC_MESSAGES", LC_MESSAGES, ""); #endif /* * We keep these set to "C" always, except transiently in pg_locale.c; see * that file for explanations. */ init_locale("LC_MONETARY", LC_MONETARY, "C"); init_locale("LC_NUMERIC", LC_NUMERIC, "C"); init_locale("LC_TIME", LC_TIME, "C"); /* * Now that we have absorbed as much as we wish to from the locale * environment, remove any LC_ALL setting, so that the environment * variables installed by pg_perm_setlocale have force. */ unsetenv("LC_ALL"); check_strxfrm_bug(); /* * Catch standard options before doing much else, in particular before we * insist on not being root. */ if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { help(progname); exit(0); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) { puts("postgres (PostgreSQL) " PG_VERSION); exit(0); } /* * In addition to the above, we allow "--describe-config" and "-C var" * to be called by root. This is reasonably safe since these are * read-only activities. The -C case is important because pg_ctl may * try to invoke it while still holding administrator privileges on * Windows. Note that while -C can normally be in any argv position, * if you want to bypass the root check you must put it first. This * reduces the risk that we might misinterpret some other mode's -C * switch as being the postmaster/postgres one. */ if (strcmp(argv[1], "--describe-config") == 0) do_check_root = false; else if (argc > 2 && strcmp(argv[1], "-C") == 0) do_check_root = false; } /* * Make sure we are not running as root, unless it's safe for the selected * option. */ if (do_check_root) check_root(progname); /* * Dispatch to one of various subprograms depending on first argument. */ #ifdef EXEC_BACKEND if (argc > 1 && strncmp(argv[1], "--fork", 6) == 0) SubPostmasterMain(argc, argv); /* does not return */ #endif #ifdef WIN32 /* * Start our win32 signal implementation * * SubPostmasterMain() will do this for itself, but the remaining modes * need it here */ pgwin32_signal_initialize(); #endif if (argc > 1 && strcmp(argv[1], "--boot") == 0) AuxiliaryProcessMain(argc, argv); /* does not return */ else if (argc > 1 && strcmp(argv[1], "--describe-config") == 0) GucInfoMain(); /* does not return */ else if (argc > 1 && strcmp(argv[1], "--single") == 0) PostgresMain(argc, argv, NULL, /* no dbname */ strdup(get_user_name_or_exit(progname))); /* does not return */ else PostmasterMain(argc, argv); /* does not return */ abort(); /* should not get here */ }
/* * CheckMyDatabase -- fetch information from the pg_database entry for our DB */ static void CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connections) { HeapTuple tup; Form_pg_database dbform; char *collate; char *ctype; /* Fetch our pg_database row normally, via syscache */ tup = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for database %u", MyDatabaseId); dbform = (Form_pg_database) GETSTRUCT(tup); /* This recheck is strictly paranoia */ if (strcmp(name, NameStr(dbform->datname)) != 0) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" has disappeared from pg_database", name), errdetail("Database OID %u now seems to belong to \"%s\".", MyDatabaseId, NameStr(dbform->datname)))); /* * Check permissions to connect to the database. * * These checks are not enforced when in standalone mode, so that there is * a way to recover from disabling all access to all databases, for * example "UPDATE pg_database SET datallowconn = false;". * * We do not enforce them for autovacuum worker processes either. */ if (IsUnderPostmaster && !IsAutoVacuumWorkerProcess()) { /* * Check that the database is currently allowing connections. */ if (!dbform->datallowconn && !override_allow_connections) ereport(FATAL, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("database \"%s\" is not currently accepting connections", name))); /* * Check privilege to connect to the database. (The am_superuser test * is redundant, but since we have the flag, might as well check it * and save a few cycles.) */ if (!am_superuser && pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CONNECT) != ACLCHECK_OK) ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for database \"%s\"", name), errdetail("User does not have CONNECT privilege."))); /* * Check connection limit for this database. * * There is a race condition here --- we create our PGPROC before * checking for other PGPROCs. If two backends did this at about the * same time, they might both think they were over the limit, while * ideally one should succeed and one fail. Getting that to work * exactly seems more trouble than it is worth, however; instead we * just document that the connection limit is approximate. */ if (dbform->datconnlimit >= 0 && !am_superuser && CountDBConnections(MyDatabaseId) > dbform->datconnlimit) ereport(FATAL, (errcode(ERRCODE_TOO_MANY_CONNECTIONS), errmsg("too many connections for database \"%s\"", name))); } /* * OK, we're golden. Next to-do item is to save the encoding info out of * the pg_database tuple. */ SetDatabaseEncoding(dbform->encoding); /* Record it as a GUC internal option, too */ SetConfigOption("server_encoding", GetDatabaseEncodingName(), PGC_INTERNAL, PGC_S_OVERRIDE); /* If we have no other source of client_encoding, use server encoding */ SetConfigOption("client_encoding", GetDatabaseEncodingName(), PGC_BACKEND, PGC_S_DYNAMIC_DEFAULT); /* assign locale variables */ collate = NameStr(dbform->datcollate); ctype = NameStr(dbform->datctype); if (pg_perm_setlocale(LC_COLLATE, collate) == NULL) ereport(FATAL, (errmsg("database locale is incompatible with operating system"), errdetail("The database was initialized with LC_COLLATE \"%s\", " " which is not recognized by setlocale().", collate), errhint("Recreate the database with another locale or install the missing locale."))); if (pg_perm_setlocale(LC_CTYPE, ctype) == NULL) ereport(FATAL, (errmsg("database locale is incompatible with operating system"), errdetail("The database was initialized with LC_CTYPE \"%s\", " " which is not recognized by setlocale().", ctype), errhint("Recreate the database with another locale or install the missing locale."))); /* Make the locale settings visible as GUC variables, too */ SetConfigOption("lc_collate", collate, PGC_INTERNAL, PGC_S_OVERRIDE); SetConfigOption("lc_ctype", ctype, PGC_INTERNAL, PGC_S_OVERRIDE); check_strxfrm_bug(); ReleaseSysCache(tup); }