LCOV - code coverage report
Current view: top level - src/backend/main - main.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 55 119 46.2 %
Date: 2025-01-18 04:15:08 Functions: 5 7 71.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * main.c
       4             :  *    Stub main() routine for the postgres executable.
       5             :  *
       6             :  * This does some essential startup tasks for any incarnation of postgres
       7             :  * (postmaster, standalone backend, standalone bootstrap process, or a
       8             :  * separately exec'd child of a postmaster) and then dispatches to the
       9             :  * proper FooMain() routine for the incarnation.
      10             :  *
      11             :  *
      12             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
      13             :  * Portions Copyright (c) 1994, Regents of the University of California
      14             :  *
      15             :  *
      16             :  * IDENTIFICATION
      17             :  *    src/backend/main/main.c
      18             :  *
      19             :  *-------------------------------------------------------------------------
      20             :  */
      21             : #include "postgres.h"
      22             : 
      23             : #include <unistd.h>
      24             : 
      25             : #if defined(WIN32)
      26             : #include <crtdbg.h>
      27             : #endif
      28             : 
      29             : #if defined(__NetBSD__)
      30             : #include <sys/param.h>
      31             : #endif
      32             : 
      33             : #include "bootstrap/bootstrap.h"
      34             : #include "common/username.h"
      35             : #include "miscadmin.h"
      36             : #include "postmaster/postmaster.h"
      37             : #include "tcop/tcopprot.h"
      38             : #include "utils/help_config.h"
      39             : #include "utils/memutils.h"
      40             : #include "utils/pg_locale.h"
      41             : #include "utils/ps_status.h"
      42             : 
      43             : 
      44             : const char *progname;
      45             : static bool reached_main = false;
      46             : 
      47             : /* names of special must-be-first options for dispatching to subprograms */
      48             : static const char *const DispatchOptionNames[] =
      49             : {
      50             :     [DISPATCH_CHECK] = "check",
      51             :     [DISPATCH_BOOT] = "boot",
      52             :     [DISPATCH_FORKCHILD] = "forkchild",
      53             :     [DISPATCH_DESCRIBE_CONFIG] = "describe-config",
      54             :     [DISPATCH_SINGLE] = "single",
      55             :     /* DISPATCH_POSTMASTER has no name */
      56             : };
      57             : 
      58             : StaticAssertDecl(lengthof(DispatchOptionNames) == DISPATCH_POSTMASTER,
      59             :                  "array length mismatch");
      60             : 
      61             : static void startup_hacks(const char *progname);
      62             : static void init_locale(const char *categoryname, int category, const char *locale);
      63             : static void help(const char *progname);
      64             : static void check_root(const char *progname);
      65             : 
      66             : 
      67             : /*
      68             :  * Any Postgres server process begins execution here.
      69             :  */
      70             : int
      71        3308 : main(int argc, char *argv[])
      72             : {
      73        3308 :     bool        do_check_root = true;
      74        3308 :     DispatchOption dispatch_option = DISPATCH_POSTMASTER;
      75             : 
      76        3308 :     reached_main = true;
      77             : 
      78             :     /*
      79             :      * If supported on the current platform, set up a handler to be called if
      80             :      * the backend/postmaster crashes with a fatal signal or exception.
      81             :      */
      82             : #if defined(WIN32)
      83             :     pgwin32_install_crashdump_handler();
      84             : #endif
      85             : 
      86        3308 :     progname = get_progname(argv[0]);
      87             : 
      88             :     /*
      89             :      * Platform-specific startup hacks
      90             :      */
      91        3308 :     startup_hacks(progname);
      92             : 
      93             :     /*
      94             :      * Remember the physical location of the initially given argv[] array for
      95             :      * possible use by ps display.  On some platforms, the argv[] storage must
      96             :      * be overwritten in order to set the process title for ps. In such cases
      97             :      * save_ps_display_args makes and returns a new copy of the argv[] array.
      98             :      *
      99             :      * save_ps_display_args may also move the environment strings to make
     100             :      * extra room. Therefore this should be done as early as possible during
     101             :      * startup, to avoid entanglements with code that might save a getenv()
     102             :      * result pointer.
     103             :      */
     104        3308 :     argv = save_ps_display_args(argc, argv);
     105             : 
     106             :     /*
     107             :      * Fire up essential subsystems: error and memory management
     108             :      *
     109             :      * Code after this point is allowed to use elog/ereport, though
     110             :      * localization of messages may not work right away, and messages won't go
     111             :      * anywhere but stderr until GUC settings get loaded.
     112             :      */
     113        3308 :     MyProcPid = getpid();
     114        3308 :     MemoryContextInit();
     115             : 
     116             :     /*
     117             :      * Set reference point for stack-depth checking.  (There's no point in
     118             :      * enabling this before error reporting works.)
     119             :      */
     120        3308 :     (void) set_stack_base();
     121             : 
     122             :     /*
     123             :      * Set up locale information
     124             :      */
     125        3308 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("postgres"));
     126             : 
     127             :     /*
     128             :      * In the postmaster, absorb the environment values for LC_COLLATE and
     129             :      * LC_CTYPE.  Individual backends will change these later to settings
     130             :      * taken from pg_database, but the postmaster cannot do that.  If we leave
     131             :      * these set to "C" then message localization might not work well in the
     132             :      * postmaster.
     133             :      */
     134        3308 :     init_locale("LC_COLLATE", LC_COLLATE, "");
     135        3308 :     init_locale("LC_CTYPE", LC_CTYPE, "");
     136             : 
     137             :     /*
     138             :      * LC_MESSAGES will get set later during GUC option processing, but we set
     139             :      * it here to allow startup error messages to be localized.
     140             :      */
     141             : #ifdef LC_MESSAGES
     142        3308 :     init_locale("LC_MESSAGES", LC_MESSAGES, "");
     143             : #endif
     144             : 
     145             :     /*
     146             :      * We keep these set to "C" always, except transiently in pg_locale.c; see
     147             :      * that file for explanations.
     148             :      */
     149        3308 :     init_locale("LC_MONETARY", LC_MONETARY, "C");
     150        3308 :     init_locale("LC_NUMERIC", LC_NUMERIC, "C");
     151        3308 :     init_locale("LC_TIME", LC_TIME, "C");
     152             : 
     153             :     /*
     154             :      * Now that we have absorbed as much as we wish to from the locale
     155             :      * environment, remove any LC_ALL setting, so that the environment
     156             :      * variables installed by pg_perm_setlocale have force.
     157             :      */
     158        3308 :     unsetenv("LC_ALL");
     159             : 
     160             :     /*
     161             :      * Catch standard options before doing much else, in particular before we
     162             :      * insist on not being root.
     163             :      */
     164        3308 :     if (argc > 1)
     165             :     {
     166        3308 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
     167             :         {
     168           0 :             help(progname);
     169           0 :             exit(0);
     170             :         }
     171        3308 :         if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
     172             :         {
     173        1326 :             fputs(PG_BACKEND_VERSIONSTR, stdout);
     174        1326 :             exit(0);
     175             :         }
     176             : 
     177             :         /*
     178             :          * In addition to the above, we allow "--describe-config" and "-C var"
     179             :          * to be called by root.  This is reasonably safe since these are
     180             :          * read-only activities.  The -C case is important because pg_ctl may
     181             :          * try to invoke it while still holding administrator privileges on
     182             :          * Windows.  Note that while -C can normally be in any argv position,
     183             :          * if you want to bypass the root check you must put it first.  This
     184             :          * reduces the risk that we might misinterpret some other mode's -C
     185             :          * switch as being the postmaster/postgres one.
     186             :          */
     187        1982 :         if (strcmp(argv[1], "--describe-config") == 0)
     188           0 :             do_check_root = false;
     189        1982 :         else if (argc > 2 && strcmp(argv[1], "-C") == 0)
     190           0 :             do_check_root = false;
     191             :     }
     192             : 
     193             :     /*
     194             :      * Make sure we are not running as root, unless it's safe for the selected
     195             :      * option.
     196             :      */
     197        1982 :     if (do_check_root)
     198        1982 :         check_root(progname);
     199             : 
     200             :     /*
     201             :      * Dispatch to one of various subprograms depending on first argument.
     202             :      */
     203             : 
     204        1982 :     if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-')
     205         432 :         dispatch_option = parse_dispatch_option(&argv[1][2]);
     206             : 
     207        1982 :     switch (dispatch_option)
     208             :     {
     209         228 :         case DISPATCH_CHECK:
     210         228 :             BootstrapModeMain(argc, argv, true);
     211             :             break;
     212          92 :         case DISPATCH_BOOT:
     213          92 :             BootstrapModeMain(argc, argv, false);
     214             :             break;
     215           0 :         case DISPATCH_FORKCHILD:
     216             : #ifdef EXEC_BACKEND
     217             :             SubPostmasterMain(argc, argv);
     218             : #else
     219             :             Assert(false);      /* should never happen */
     220             : #endif
     221           0 :             break;
     222           0 :         case DISPATCH_DESCRIBE_CONFIG:
     223           0 :             GucInfoMain();
     224             :             break;
     225         112 :         case DISPATCH_SINGLE:
     226         112 :             PostgresSingleUserMain(argc, argv,
     227         112 :                                    strdup(get_user_name_or_exit(progname)));
     228             :             break;
     229        1550 :         case DISPATCH_POSTMASTER:
     230        1550 :             PostmasterMain(argc, argv);
     231             :             break;
     232             :     }
     233             : 
     234             :     /* the functions above should not return */
     235           0 :     abort();
     236             : }
     237             : 
     238             : /*
     239             :  * Returns the matching DispatchOption value for the given option name.  If no
     240             :  * match is found, DISPATCH_POSTMASTER is returned.
     241             :  */
     242             : DispatchOption
     243        1850 : parse_dispatch_option(const char *name)
     244             : {
     245        9480 :     for (int i = 0; i < lengthof(DispatchOptionNames); i++)
     246             :     {
     247             :         /*
     248             :          * Unlike the other dispatch options, "forkchild" takes an argument,
     249             :          * so we just look for the prefix for that one.  For non-EXEC_BACKEND
     250             :          * builds, we never want to return DISPATCH_FORKCHILD, so skip over it
     251             :          * in that case.
     252             :          */
     253        8062 :         if (i == DISPATCH_FORKCHILD)
     254             :         {
     255             : #ifdef EXEC_BACKEND
     256             :             if (strncmp(DispatchOptionNames[DISPATCH_FORKCHILD], name,
     257             :                         strlen(DispatchOptionNames[DISPATCH_FORKCHILD])) == 0)
     258             :                 return DISPATCH_FORKCHILD;
     259             : #endif
     260        1530 :             continue;
     261             :         }
     262             : 
     263        6532 :         if (strcmp(DispatchOptionNames[i], name) == 0)
     264         432 :             return (DispatchOption) i;
     265             :     }
     266             : 
     267             :     /* no match means this is a postmaster */
     268        1418 :     return DISPATCH_POSTMASTER;
     269             : }
     270             : 
     271             : /*
     272             :  * Place platform-specific startup hacks here.  This is the right
     273             :  * place to put code that must be executed early in the launch of any new
     274             :  * server process.  Note that this code will NOT be executed when a backend
     275             :  * or sub-bootstrap process is forked, unless we are in a fork/exec
     276             :  * environment (ie EXEC_BACKEND is defined).
     277             :  *
     278             :  * XXX The need for code here is proof that the platform in question
     279             :  * is too brain-dead to provide a standard C execution environment
     280             :  * without help.  Avoid adding more here, if you can.
     281             :  */
     282             : static void
     283        3308 : startup_hacks(const char *progname)
     284             : {
     285             :     /*
     286             :      * Windows-specific execution environment hacking.
     287             :      */
     288             : #ifdef WIN32
     289             :     {
     290             :         WSADATA     wsaData;
     291             :         int         err;
     292             : 
     293             :         /* Make output streams unbuffered by default */
     294             :         setvbuf(stdout, NULL, _IONBF, 0);
     295             :         setvbuf(stderr, NULL, _IONBF, 0);
     296             : 
     297             :         /* Prepare Winsock */
     298             :         err = WSAStartup(MAKEWORD(2, 2), &wsaData);
     299             :         if (err != 0)
     300             :         {
     301             :             write_stderr("%s: WSAStartup failed: %d\n",
     302             :                          progname, err);
     303             :             exit(1);
     304             :         }
     305             : 
     306             :         /*
     307             :          * By default abort() only generates a crash-dump in *non* debug
     308             :          * builds. As our Assert() / ExceptionalCondition() uses abort(),
     309             :          * leaving the default in place would make debugging harder.
     310             :          *
     311             :          * MINGW's own C runtime doesn't have _set_abort_behavior(). When
     312             :          * targeting Microsoft's UCRT with mingw, it never links to the debug
     313             :          * version of the library and thus doesn't need the call to
     314             :          * _set_abort_behavior() either.
     315             :          */
     316             : #if !defined(__MINGW32__) && !defined(__MINGW64__)
     317             :         _set_abort_behavior(_CALL_REPORTFAULT | _WRITE_ABORT_MSG,
     318             :                             _CALL_REPORTFAULT | _WRITE_ABORT_MSG);
     319             : #endif                          /* !defined(__MINGW32__) &&
     320             :                                  * !defined(__MINGW64__) */
     321             : 
     322             :         /*
     323             :          * SEM_FAILCRITICALERRORS causes more errors to be reported to
     324             :          * callers.
     325             :          *
     326             :          * We used to also specify SEM_NOGPFAULTERRORBOX, but that prevents
     327             :          * windows crash reporting from working. Which includes registered
     328             :          * just-in-time debuggers, making it unnecessarily hard to debug
     329             :          * problems on windows. Now we try to disable sources of popups
     330             :          * separately below (note that SEM_NOGPFAULTERRORBOX did not actually
     331             :          * prevent all sources of such popups).
     332             :          */
     333             :         SetErrorMode(SEM_FAILCRITICALERRORS);
     334             : 
     335             :         /*
     336             :          * Show errors on stderr instead of popup box (note this doesn't
     337             :          * affect errors originating in the C runtime, see below).
     338             :          */
     339             :         _set_error_mode(_OUT_TO_STDERR);
     340             : 
     341             :         /*
     342             :          * In DEBUG builds, errors, including assertions, C runtime errors are
     343             :          * reported via _CrtDbgReport. By default such errors are displayed
     344             :          * with a popup (even with NOGPFAULTERRORBOX), preventing forward
     345             :          * progress. Instead report such errors stderr (and the debugger).
     346             :          * This is C runtime specific and thus the above incantations aren't
     347             :          * sufficient to suppress these popups.
     348             :          */
     349             :         _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
     350             :         _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
     351             :         _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
     352             :         _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
     353             :         _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
     354             :         _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
     355             :     }
     356             : #endif                          /* WIN32 */
     357        3308 : }
     358             : 
     359             : 
     360             : /*
     361             :  * Make the initial permanent setting for a locale category.  If that fails,
     362             :  * perhaps due to LC_foo=invalid in the environment, use locale C.  If even
     363             :  * that fails, perhaps due to out-of-memory, the entire startup fails with it.
     364             :  * When this returns, we are guaranteed to have a setting for the given
     365             :  * category's environment variable.
     366             :  */
     367             : static void
     368       19848 : init_locale(const char *categoryname, int category, const char *locale)
     369             : {
     370       19848 :     if (pg_perm_setlocale(category, locale) == NULL &&
     371           0 :         pg_perm_setlocale(category, "C") == NULL)
     372           0 :         elog(FATAL, "could not adopt \"%s\" locale nor C locale for %s",
     373             :              locale, categoryname);
     374       19848 : }
     375             : 
     376             : 
     377             : 
     378             : /*
     379             :  * Help display should match the options accepted by PostmasterMain()
     380             :  * and PostgresMain().
     381             :  *
     382             :  * XXX On Windows, non-ASCII localizations of these messages only display
     383             :  * correctly if the console output code page covers the necessary characters.
     384             :  * Messages emitted in write_console() do not exhibit this problem.
     385             :  */
     386             : static void
     387           0 : help(const char *progname)
     388             : {
     389           0 :     printf(_("%s is the PostgreSQL server.\n\n"), progname);
     390           0 :     printf(_("Usage:\n  %s [OPTION]...\n\n"), progname);
     391           0 :     printf(_("Options:\n"));
     392           0 :     printf(_("  -B NBUFFERS        number of shared buffers\n"));
     393           0 :     printf(_("  -c NAME=VALUE      set run-time parameter\n"));
     394           0 :     printf(_("  -C NAME            print value of run-time parameter, then exit\n"));
     395           0 :     printf(_("  -d 1-5             debugging level\n"));
     396           0 :     printf(_("  -D DATADIR         database directory\n"));
     397           0 :     printf(_("  -e                 use European date input format (DMY)\n"));
     398           0 :     printf(_("  -F                 turn fsync off\n"));
     399           0 :     printf(_("  -h HOSTNAME        host name or IP address to listen on\n"));
     400           0 :     printf(_("  -i                 enable TCP/IP connections (deprecated)\n"));
     401           0 :     printf(_("  -k DIRECTORY       Unix-domain socket location\n"));
     402             : #ifdef USE_SSL
     403           0 :     printf(_("  -l                 enable SSL connections\n"));
     404             : #endif
     405           0 :     printf(_("  -N MAX-CONNECT     maximum number of allowed connections\n"));
     406           0 :     printf(_("  -p PORT            port number to listen on\n"));
     407           0 :     printf(_("  -s                 show statistics after each query\n"));
     408           0 :     printf(_("  -S WORK-MEM        set amount of memory for sorts (in kB)\n"));
     409           0 :     printf(_("  -V, --version      output version information, then exit\n"));
     410           0 :     printf(_("  --NAME=VALUE       set run-time parameter\n"));
     411           0 :     printf(_("  --describe-config  describe configuration parameters, then exit\n"));
     412           0 :     printf(_("  -?, --help         show this help, then exit\n"));
     413             : 
     414           0 :     printf(_("\nDeveloper options:\n"));
     415           0 :     printf(_("  -f s|i|o|b|t|n|m|h forbid use of some plan types\n"));
     416           0 :     printf(_("  -O                 allow system table structure changes\n"));
     417           0 :     printf(_("  -P                 disable system indexes\n"));
     418           0 :     printf(_("  -t pa|pl|ex        show timings after each query\n"));
     419           0 :     printf(_("  -T                 send SIGABRT to all backend processes if one dies\n"));
     420           0 :     printf(_("  -W NUM             wait NUM seconds to allow attach from a debugger\n"));
     421             : 
     422           0 :     printf(_("\nOptions for single-user mode:\n"));
     423           0 :     printf(_("  --single           selects single-user mode (must be first argument)\n"));
     424           0 :     printf(_("  DBNAME             database name (defaults to user name)\n"));
     425           0 :     printf(_("  -d 0-5             override debugging level\n"));
     426           0 :     printf(_("  -E                 echo statement before execution\n"));
     427           0 :     printf(_("  -j                 do not use newline as interactive query delimiter\n"));
     428           0 :     printf(_("  -r FILENAME        send stdout and stderr to given file\n"));
     429             : 
     430           0 :     printf(_("\nOptions for bootstrapping mode:\n"));
     431           0 :     printf(_("  --boot             selects bootstrapping mode (must be first argument)\n"));
     432           0 :     printf(_("  --check            selects check mode (must be first argument)\n"));
     433           0 :     printf(_("  DBNAME             database name (mandatory argument in bootstrapping mode)\n"));
     434           0 :     printf(_("  -r FILENAME        send stdout and stderr to given file\n"));
     435             : 
     436           0 :     printf(_("\nPlease read the documentation for the complete list of run-time\n"
     437             :              "configuration settings and how to set them on the command line or in\n"
     438             :              "the configuration file.\n\n"
     439             :              "Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     440           0 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
     441           0 : }
     442             : 
     443             : 
     444             : 
     445             : static void
     446        1982 : check_root(const char *progname)
     447             : {
     448             : #ifndef WIN32
     449        1982 :     if (geteuid() == 0)
     450             :     {
     451           0 :         write_stderr("\"root\" execution of the PostgreSQL server is not permitted.\n"
     452             :                      "The server must be started under an unprivileged user ID to prevent\n"
     453             :                      "possible system security compromise.  See the documentation for\n"
     454             :                      "more information on how to properly start the server.\n");
     455           0 :         exit(1);
     456             :     }
     457             : 
     458             :     /*
     459             :      * Also make sure that real and effective uids are the same. Executing as
     460             :      * a setuid program from a root shell is a security hole, since on many
     461             :      * platforms a nefarious subroutine could setuid back to root if real uid
     462             :      * is root.  (Since nobody actually uses postgres as a setuid program,
     463             :      * trying to actively fix this situation seems more trouble than it's
     464             :      * worth; we'll just expend the effort to check for it.)
     465             :      */
     466        1982 :     if (getuid() != geteuid())
     467             :     {
     468           0 :         write_stderr("%s: real and effective user IDs must match\n",
     469             :                      progname);
     470           0 :         exit(1);
     471             :     }
     472             : #else                           /* WIN32 */
     473             :     if (pgwin32_is_admin())
     474             :     {
     475             :         write_stderr("Execution of PostgreSQL by a user with administrative permissions is not\n"
     476             :                      "permitted.\n"
     477             :                      "The server must be started under an unprivileged user ID to prevent\n"
     478             :                      "possible system security compromises.  See the documentation for\n"
     479             :                      "more information on how to properly start the server.\n");
     480             :         exit(1);
     481             :     }
     482             : #endif                          /* WIN32 */
     483        1982 : }
     484             : 
     485             : /*
     486             :  * At least on linux, set_ps_display() breaks /proc/$pid/environ. The
     487             :  * sanitizer library uses /proc/$pid/environ to implement getenv() as it wants
     488             :  * to work independent of libc. When just using undefined and alignment
     489             :  * sanitizers, the sanitizer library is only initialized when the first error
     490             :  * occurs, by which time we've often already called set_ps_display(),
     491             :  * preventing the sanitizer libraries from seeing the options.
     492             :  *
     493             :  * We can work around that by defining __ubsan_default_options, a weak symbol
     494             :  * libsanitizer uses to get defaults from the application, and return
     495             :  * getenv("UBSAN_OPTIONS"). But only if main already was reached, so that we
     496             :  * don't end up relying on a not-yet-working getenv().
     497             :  *
     498             :  * As this function won't get called when not running a sanitizer, it doesn't
     499             :  * seem necessary to only compile it conditionally.
     500             :  */
     501             : const char *__ubsan_default_options(void);
     502             : const char *
     503           0 : __ubsan_default_options(void)
     504             : {
     505             :     /* don't call libc before it's guaranteed to be initialized */
     506           0 :     if (!reached_main)
     507           0 :         return "";
     508             : 
     509           0 :     return getenv("UBSAN_OPTIONS");
     510             : }

Generated by: LCOV version 1.14