/* * Make the initial permanent setting for a locale category. If that fails, * perhaps due to LC_foo=invalid in the environment, use locale C. If even * that fails, perhaps due to out-of-memory, the entire startup fails with it. * When this returns, we are guaranteed to have a setting for the given * category's environment variable. */ static void init_locale(int category, const char *locale) { if (pg_perm_setlocale(category, locale) == NULL && pg_perm_setlocale(category, "C") == NULL) elog(FATAL, "could not adopt C locale"); }
/* * Make the initial permanent setting for a locale category. If that fails, * perhaps due to LC_foo=invalid in the environment, use locale C. If even * that fails, perhaps due to out-of-memory, the entire startup fails with it. * When this returns, we are guaranteed to have a setting for the given * category's environment variable. */ static void init_locale(const char *categoryname, int category, const char *locale) { if (pg_perm_setlocale(category, locale) == NULL && pg_perm_setlocale(category, "C") == NULL) elog(FATAL, "could not adopt \"%s\" locale nor C locale for %s", locale, categoryname); }
/* * We allow LC_MESSAGES to actually be set globally. * * Note: we normally disallow value = "" because it wouldn't have consistent * semantics (it'd effectively just use the previous value). However, this * is the value passed for PGC_S_DEFAULT, so don't complain in that case, * not even if the attempted setting fails due to invalid environment value. * The idea there is just to accept the environment setting *if possible* * during startup, until we can read the proper value from postgresql.conf. */ const char * locale_messages_assign(const char *value, bool doit, GucSource source) { if (*value == '\0' && source != PGC_S_DEFAULT) return NULL; /* * LC_MESSAGES category does not exist everywhere, but accept it anyway * * On Windows, we can't even check the value, so the non-doit case is a * no-op */ #ifdef LC_MESSAGES if (doit) { if (!pg_perm_setlocale(LC_MESSAGES, value)) if (source != PGC_S_DEFAULT) return NULL; } #ifndef WIN32 else value = locale_xxx_assign(LC_MESSAGES, value, false, source); #endif /* WIN32 */ #endif /* LC_MESSAGES */ return value; }
void assign_locale_messages(const char *newval, void *extra) { /* * LC_MESSAGES category does not exist everywhere, but accept it anyway. * We ignore failure, as per comment above. */ #ifdef LC_MESSAGES (void) pg_perm_setlocale(LC_MESSAGES, newval); #endif }
/* * CheckMyDatabase -- fetch information from the pg_database entry for our DB */ static void CheckMyDatabase(const char *name, bool am_superuser) { 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) 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 && CountDBBackends(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); ReleaseSysCache(tup); }
/* * Any Postgres server process begins execution here. */ int main(int argc, char *argv[]) { 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 /* * 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) pg_perm_setlocale(LC_COLLATE, env_locale); else pg_perm_setlocale(LC_COLLATE, ""); if ((env_locale = getenv("LC_CTYPE")) != NULL) pg_perm_setlocale(LC_CTYPE, env_locale); else pg_perm_setlocale(LC_CTYPE, ""); } #else pg_perm_setlocale(LC_COLLATE, ""); pg_perm_setlocale(LC_CTYPE, ""); #endif #ifdef LC_MESSAGES pg_perm_setlocale(LC_MESSAGES, ""); #endif /* * We keep these set to "C" always, except transiently in pg_locale.c; see * that file for explanations. */ pg_perm_setlocale(LC_MONETARY, "C"); pg_perm_setlocale(LC_NUMERIC, "C"); pg_perm_setlocale(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"); /* * Catch standard options before doing much else */ 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); } } /* * Make sure we are not running as 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) exit(SubPostmasterMain(argc, argv)); #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 */ if (argc > 1 && strcmp(argv[1], "--describe-config") == 0) exit(GucInfoMain()); if (argc > 1 && strcmp(argv[1], "--single") == 0) exit(PostgresMain(argc, argv, get_current_username(progname))); exit(PostmasterMain(argc, argv)); }
/* * 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) pg_perm_setlocale(LC_COLLATE, env_locale); else pg_perm_setlocale(LC_COLLATE, ""); if ((env_locale = getenv("LC_CTYPE")) != NULL) pg_perm_setlocale(LC_CTYPE, env_locale); else pg_perm_setlocale(LC_CTYPE, ""); } #else pg_perm_setlocale(LC_COLLATE, ""); pg_perm_setlocale(LC_CTYPE, ""); #endif #ifdef LC_MESSAGES pg_perm_setlocale(LC_MESSAGES, ""); #endif /* * We keep these set to "C" always, except transiently in pg_locale.c; see * that file for explanations. */ pg_perm_setlocale(LC_MONETARY, "C"); pg_perm_setlocale(LC_NUMERIC, "C"); pg_perm_setlocale(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"); /* * 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 wanna bypass the root check you gotta 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 */ }