diff options
Diffstat (limited to 'src/backend/postmaster/postmaster.c')
-rw-r--r-- | src/backend/postmaster/postmaster.c | 209 |
1 files changed, 57 insertions, 152 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 8ea5c187588..3f773336411 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.592 2009/08/28 18:23:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.593 2009/08/29 19:26:51 tgl Exp $ * * NOTES * @@ -327,6 +327,7 @@ static void SIGHUP_handler(SIGNAL_ARGS); static void pmdie(SIGNAL_ARGS); static void reaper(SIGNAL_ARGS); static void sigusr1_handler(SIGNAL_ARGS); +static void startup_die(SIGNAL_ARGS); static void dummy_handler(SIGNAL_ARGS); static void CleanupBackend(int pid, int exitstatus); static void HandleChildCrash(int pid, int exitstatus, const char *procname); @@ -1561,7 +1562,8 @@ ProcessStartupPacket(Port *port, bool SSLdone) if (proto == CANCEL_REQUEST_CODE) { processCancelRequest(port, buf); - return 127; /* XXX */ + /* Not really an error, but we don't want to proceed further */ + return STATUS_ERROR; } if (proto == NEGOTIATE_SSL_CODE && !SSLdone) @@ -1623,10 +1625,10 @@ retry1: /* * Now fetch parameters out of startup packet and save them into the Port * structure. All data structures attached to the Port struct must be - * allocated in TopMemoryContext so that they won't disappear when we pass - * them to PostgresMain (see BackendRun). We need not worry about leaking - * this storage on failure, since we aren't in the postmaster process - * anymore. + * allocated in TopMemoryContext so that they will remain available in + * a running backend (even after PostmasterContext is destroyed). We need + * not worry about leaking this storage on failure, since we aren't in the + * postmaster process anymore. */ oldcontext = MemoryContextSwitchTo(TopMemoryContext); @@ -2292,13 +2294,6 @@ reaper(SIGNAL_ARGS) pmState = PM_RUN; /* - * Load the flat authorization file into postmaster's cache. The - * startup process has recomputed this from the database contents, - * so we wait till it finishes before loading it. - */ - load_role(); - - /* * Crank up the background writer, if we didn't do that already * when we entered consistent recovery state. It doesn't matter * if this fails, we'll just try again later. @@ -3054,7 +3049,7 @@ BackendStartup(Port *port) /* Close the postmaster's sockets */ ClosePostmasterPorts(false); - /* Perform additional initialization and client authentication */ + /* Perform additional initialization and collect startup packet */ BackendInitialize(port); /* And run the backend */ @@ -3130,38 +3125,8 @@ report_fork_failure_to_client(Port *port, int errnum) /* - * split_opts -- split a string of options and append it to an argv array - * - * NB: the string is destructively modified! - * - * Since no current POSTGRES arguments require any quoting characters, - * we can use the simple-minded tactic of assuming each set of space- - * delimited characters is a separate argv element. - * - * If you don't like that, well, we *used* to pass the whole option string - * as ONE argument to execl(), which was even less intelligent... - */ -static void -split_opts(char **argv, int *argcp, char *s) -{ - while (s && *s) - { - while (isspace((unsigned char) *s)) - ++s; - if (*s == '\0') - break; - argv[(*argcp)++] = s; - while (*s && !isspace((unsigned char) *s)) - ++s; - if (*s) - *s++ = '\0'; - } -} - - -/* * BackendInitialize -- initialize an interactive (postmaster-child) - * backend process, and perform client authentication. + * backend process, and collect the client's startup packet. * * returns: nothing. Will not return at all if there's any failure. * @@ -3183,13 +3148,14 @@ BackendInitialize(Port *port) /* * PreAuthDelay is a debugging aid for investigating problems in the * authentication cycle: it can be set in postgresql.conf to allow time to - * attach to the newly-forked backend with a debugger. (See also the -W - * backend switch, which we allow clients to pass through PGOPTIONS, but + * attach to the newly-forked backend with a debugger. (See also + * PostAuthDelay, which we allow clients to pass through PGOPTIONS, but * it is not honored until after authentication.) */ if (PreAuthDelay > 0) pg_usleep(PreAuthDelay * 1000000L); + /* This flag will remain set until InitPostgres finishes authentication */ ClientAuthInProgress = true; /* limit visibility of log messages */ /* save process start time */ @@ -3218,15 +3184,15 @@ BackendInitialize(Port *port) #endif /* - * We arrange for a simple exit(1) if we receive SIGTERM or SIGQUIT during - * any client authentication related communication. Otherwise the + * We arrange for a simple exit(1) if we receive SIGTERM or SIGQUIT + * or timeout while trying to collect the startup packet. Otherwise the * postmaster cannot shutdown the database FAST or IMMED cleanly if a - * buggy client blocks a backend during authentication. + * buggy client fails to send the packet promptly. */ - pqsignal(SIGTERM, authdie); - pqsignal(SIGQUIT, authdie); - pqsignal(SIGALRM, authdie); - PG_SETMASK(&AuthBlockSig); + pqsignal(SIGTERM, startup_die); + pqsignal(SIGQUIT, startup_die); + pqsignal(SIGALRM, startup_die); + PG_SETMASK(&StartupBlockSig); /* * Get the remote host name and port for logging and status display. @@ -3265,42 +3231,13 @@ BackendInitialize(Port *port) port->remote_port = strdup(remote_port); /* - * In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.conf - * etcetera from the postmaster, and have to load them ourselves. Build - * the PostmasterContext (which didn't exist before, in this process) to - * contain the data. - * - * FIXME: [fork/exec] Ugh. Is there a way around this overhead? - */ -#ifdef EXEC_BACKEND - Assert(PostmasterContext == NULL); - PostmasterContext = AllocSetContextCreate(TopMemoryContext, - "Postmaster", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); - MemoryContextSwitchTo(PostmasterContext); - - if (!load_hba()) - { - /* - * It makes no sense to continue if we fail to load the HBA file, - * since there is no way to connect to the database in this case. - */ - ereport(FATAL, - (errmsg("could not load pg_hba.conf"))); - } - load_ident(); - load_role(); -#endif - - /* - * Ready to begin client interaction. We will give up and exit(0) after a + * Ready to begin client interaction. We will give up and exit(1) after a * time delay, so that a broken client can't hog a connection - * indefinitely. PreAuthDelay doesn't count against the time limit. + * indefinitely. PreAuthDelay and any DNS interactions above don't count + * against the time limit. */ if (!enable_sig_alarm(AuthenticationTimeout * 1000, false)) - elog(FATAL, "could not set timer for authorization timeout"); + elog(FATAL, "could not set timer for startup packet timeout"); /* * Receive the startup packet (which might turn out to be a cancel request @@ -3308,6 +3245,10 @@ BackendInitialize(Port *port) */ status = ProcessStartupPacket(port, false); + /* + * Stop here if it was bad or a cancel packet. ProcessStartupPacket + * already did any appropriate error reporting. + */ if (status != STATUS_OK) proc_exit(0); @@ -3319,22 +3260,11 @@ BackendInitialize(Port *port) update_process_title ? "authentication" : ""); /* - * Now perform authentication exchange. - */ - ClientAuthentication(port); /* might not return, if failure */ - - /* - * Done with authentication. Disable timeout, and prevent SIGTERM/SIGQUIT - * again until backend startup is complete. + * Disable the timeout, and prevent SIGTERM/SIGQUIT again. */ if (!disable_sig_alarm(false)) - elog(FATAL, "could not disable timer for authorization timeout"); + elog(FATAL, "could not disable timer for startup packet timeout"); PG_SETMASK(&BlockSig); - - if (Log_connections) - ereport(LOG, - (errmsg("connection authorized: user=%s database=%s", - port->user_name, port->database_name))); } @@ -3366,22 +3296,15 @@ BackendRun(Port *port) TimestampDifference(0, port->SessionStartTime, &secs, &usecs); srandom((unsigned int) (MyProcPid ^ usecs)); - /* ---------------- + /* * Now, build the argv vector that will be given to PostgresMain. * - * The layout of the command line is - * postgres [secure switches] -y databasename [insecure switches] - * where the switches after -y come from the client request. - * * The maximum possible number of commandline arguments that could come - * from ExtraOptions or port->cmdline_options is (strlen + 1) / 2; see - * split_opts(). - * ---------------- + * from ExtraOptions is (strlen(ExtraOptions) + 1) / 2; see + * pg_split_opts(). */ - maxac = 10; /* for fixed args supplied below */ + maxac = 5; /* for fixed args supplied below */ maxac += (strlen(ExtraOptions) + 1) / 2; - if (port->cmdline_options) - maxac += (strlen(port->cmdline_options) + 1) / 2; av = (char **) MemoryContextAlloc(TopMemoryContext, maxac * sizeof(char *)); @@ -3390,42 +3313,22 @@ BackendRun(Port *port) av[ac++] = "postgres"; /* - * Pass any backend switches specified with -o in the postmaster's own + * Pass any backend switches specified with -o on the postmaster's own * command line. We assume these are secure. (It's OK to mangle * ExtraOptions now, since we're safely inside a subprocess.) */ - split_opts(av, &ac, ExtraOptions); + pg_split_opts(av, &ac, ExtraOptions); /* - * Tell the backend it is being called from the postmaster, and which - * database to use. -y marks the end of secure switches. + * Tell the backend which database to use. */ - av[ac++] = "-y"; av[ac++] = port->database_name; - /* - * Pass the (insecure) option switches from the connection request. (It's - * OK to mangle port->cmdline_options now.) - */ - if (port->cmdline_options) - split_opts(av, &ac, port->cmdline_options); - av[ac] = NULL; Assert(ac < maxac); /* - * Release postmaster's working memory context so that backend can recycle - * the space. Note this does not trash *MyProcPort, because ConnCreate() - * allocated that space with malloc() ... else we'd need to copy the Port - * data here. Also, subsidiary data such as the username isn't lost - * either; see ProcessStartupPacket(). - */ - MemoryContextSwitchTo(TopMemoryContext); - MemoryContextDelete(PostmasterContext); - PostmasterContext = NULL; - - /* * Debug: print arguments being passed to backend */ ereport(DEBUG3, @@ -3437,7 +3340,11 @@ BackendRun(Port *port) ereport(DEBUG3, (errmsg_internal(")"))); - ClientAuthInProgress = false; /* client_min_messages is active now */ + /* + * Make sure we aren't in PostmasterContext anymore. (We can't delete it + * just yet, though, because InitPostgres will need the HBA data.) + */ + MemoryContextSwitchTo(TopMemoryContext); return (PostgresMain(ac, av, port->user_name)); } @@ -3833,7 +3740,6 @@ SubPostmasterMain(int argc, char *argv[]) errmsg("out of memory"))); #endif - /* Check we got appropriate args */ if (argc < 3) elog(FATAL, "invalid subpostmaster invocation"); @@ -3901,7 +3807,7 @@ SubPostmasterMain(int argc, char *argv[]) #endif /* - * Perform additional initialization and client authentication. + * Perform additional initialization and collect startup packet. * * We want to do this before InitProcess() for a couple of reasons: 1. * so that we aren't eating up a PGPROC slot while waiting on the @@ -4075,13 +3981,6 @@ sigusr1_handler(SIGNAL_ARGS) pmState == PM_RECOVERY) { /* - * Load the flat authorization file into postmaster's cache. The - * startup process won't have recomputed this from the database yet, - * so it may change following recovery. - */ - load_role(); - - /* * Likewise, start other special children as needed. */ Assert(PgStatPID == 0); @@ -4094,14 +3993,6 @@ sigusr1_handler(SIGNAL_ARGS) pmState = PM_RECOVERY_CONSISTENT; } - if (CheckPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE)) - { - /* - * Authorization file has changed. - */ - load_role(); - } - if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) && PgArchPID != 0) { @@ -4144,6 +4035,20 @@ sigusr1_handler(SIGNAL_ARGS) errno = save_errno; } +/* + * Timeout or shutdown signal from postmaster while processing startup packet. + * Cleanup and exit(1). + * + * XXX: possible future improvement: try to send a message indicating + * why we are disconnecting. Problem is to be sure we don't block while + * doing so, nor mess up SSL initialization. In practice, if the client + * has wedged here, it probably couldn't do anything with the message anyway. + */ +static void +startup_die(SIGNAL_ARGS) +{ + proc_exit(1); +} /* * Dummy signal handler |