Index: src/backend/postmaster/postmaster.c =================================================================== RCS file: /cvsroot/pgsql-server/src/backend/postmaster/postmaster.c,v retrieving revision 1.315 diff -c -c -r1.315 postmaster.c *** src/backend/postmaster/postmaster.c 26 Apr 2003 02:57:14 -0000 1.315 --- src/backend/postmaster/postmaster.c 1 May 2003 19:53:54 -0000 *************** *** 256,266 **** static void CleanupProc(int pid, int exitstatus); static void LogChildExit(int lev, const char *procname, int pid, int exitstatus); ! static int DoBackend(Port *port); void ExitPostmaster(int status); static void usage(const char *); static int ServerLoop(void); static int BackendStartup(Port *port); static int ProcessStartupPacket(Port *port, bool SSLdone); static void processCancelRequest(Port *port, void *pkt); static int initMasks(fd_set *rmask, fd_set *wmask); --- 256,267 ---- static void CleanupProc(int pid, int exitstatus); static void LogChildExit(int lev, const char *procname, int pid, int exitstatus); ! static int BackendFinalize(Port *port); void ExitPostmaster(int status); static void usage(const char *); static int ServerLoop(void); static int BackendStartup(Port *port); + static void BackendFork(Port *port, Backend *bn); static int ProcessStartupPacket(Port *port, bool SSLdone); static void processCancelRequest(Port *port, void *pkt); static int initMasks(fd_set *rmask, fd_set *wmask); *************** *** 570,575 **** --- 571,579 ---- SetDataDir(potential_DataDir); ProcessConfigFile(PGC_POSTMASTER); + #ifdef EXEC_BACKEND + write_nondefault_variables(PGC_POSTMASTER); + #endif /* * Check for invalid combinations of GUC settings. *************** *** 1231,1237 **** * 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 DoBackend). We need not worry * about leaking this storage on failure, since we aren't in the postmaster * process anymore. */ --- 1235,1241 ---- * 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 BackendFinalize). We need not worry * about leaking this storage on failure, since we aren't in the postmaster * process anymore. */ *************** *** 1568,1573 **** --- 1572,1580 ---- elog(LOG, "Received SIGHUP, reloading configuration files"); SignalChildren(SIGHUP); ProcessConfigFile(PGC_SIGHUP); + #ifdef EXEC_BACKEND + write_nondefault_variables(PGC_SIGHUP); + #endif load_hba(); load_ident(); } *************** *** 2053,2080 **** pid = fork(); if (pid == 0) /* child */ ! { ! int status; ! ! #ifdef LINUX_PROFILE ! setitimer(ITIMER_PROF, &prof_itimer, NULL); ! #endif ! ! #ifdef __BEOS__ ! /* Specific beos backend startup actions */ ! beos_backend_startup(); ! #endif ! free(bn); ! ! status = DoBackend(port); ! if (status != 0) ! { ! elog(LOG, "connection startup failed"); ! proc_exit(status); ! } ! else ! proc_exit(0); ! } /* in parent, error */ if (pid < 0) --- 2060,2066 ---- pid = fork(); if (pid == 0) /* child */ ! BackendFork(port, bn); /* never returns */ /* in parent, error */ if (pid < 0) *************** *** 2108,2113 **** --- 2094,2124 ---- } + static void + BackendFork(Port *port, Backend *bn) + { + int status; + + #ifdef LINUX_PROFILE + setitimer(ITIMER_PROF, &prof_itimer, NULL); + #endif + + #ifdef __BEOS__ + /* Specific beos backend startup actions */ + beos_backend_startup(); + #endif + free(bn); + + status = BackendFinalize(port); + if (status != 0) + { + elog(LOG, "connection startup failed"); + proc_exit(status); + } + else + proc_exit(0); + } + /* * Try to report backend fork() failure to client before we close the * connection. Since we do not care to risk blocking the postmaster on *************** *** 2173,2179 **** } /* ! * DoBackend -- perform authentication, and if successful, set up the * backend's argument list and invoke backend main(). * * This used to perform an execv() but we no longer exec the backend; --- 2184,2190 ---- } /* ! * BackendFinalize -- perform authentication, and if successful, set up the * backend's argument list and invoke backend main(). * * This used to perform an execv() but we no longer exec the backend; *************** *** 2184,2190 **** * If PostgresMain() fails, return status. */ static int ! DoBackend(Port *port) { char *remote_host; char **av; --- 2195,2201 ---- * If PostgresMain() fails, return status. */ static int ! BackendFinalize(Port *port) { char *remote_host; char **av; *************** *** 2221,2226 **** --- 2232,2241 ---- /* Reset MyProcPid to new backend's pid */ MyProcPid = getpid(); + #ifdef EXEC_BACKEND + read_nondefault_variables(); + #endif + /* * Initialize libpq and enable reporting of elog errors to the client. * Must do this now because authentication uses libpq to send *************** *** 2248,2254 **** unsigned short remote_port; char *host_addr; #ifdef HAVE_IPV6 ! char ip_hostinfo[INET6_ADDRSTRLEN]; #else char ip_hostinfo[INET_ADDRSTRLEN]; #endif --- 2263,2269 ---- unsigned short remote_port; char *host_addr; #ifdef HAVE_IPV6 ! char ip_hostinfo[INET6_ADDRSTRLEN]; #else char ip_hostinfo[INET_ADDRSTRLEN]; #endif *************** *** 2294,2300 **** } else { ! /* not AF_INET */ remote_host = "[local]"; if (Log_connections) --- 2309,2315 ---- } else { ! /* not AF_INET */ remote_host = "[local]"; if (Log_connections) *************** *** 2318,2324 **** * indefinitely. PreAuthDelay doesn't count against the time limit. */ if (!enable_sig_alarm(AuthenticationTimeout * 1000, false)) ! elog(FATAL, "DoBackend: Unable to set timer for auth timeout"); /* * Receive the startup packet (which might turn out to be a cancel --- 2333,2339 ---- * indefinitely. PreAuthDelay doesn't count against the time limit. */ if (!enable_sig_alarm(AuthenticationTimeout * 1000, false)) ! elog(FATAL, "BackendFinalize: Unable to set timer for auth timeout"); /* * Receive the startup packet (which might turn out to be a cancel *************** *** 2347,2353 **** * SIGTERM/SIGQUIT again until backend startup is complete. */ if (!disable_sig_alarm(false)) ! elog(FATAL, "DoBackend: Unable to disable timer for auth timeout"); PG_SETMASK(&BlockSig); if (Log_connections) --- 2362,2368 ---- * SIGTERM/SIGQUIT again until backend startup is complete. */ if (!disable_sig_alarm(false)) ! elog(FATAL, "BackendFinalize: Unable to disable timer for auth timeout"); PG_SETMASK(&BlockSig); if (Log_connections) Index: src/backend/utils/misc/guc.c =================================================================== RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v retrieving revision 1.119 diff -c -c -r1.119 guc.c *** src/backend/utils/misc/guc.c 25 Apr 2003 19:45:09 -0000 1.119 --- src/backend/utils/misc/guc.c 1 May 2003 19:53:57 -0000 *************** *** 60,65 **** --- 60,68 ---- #define PG_KRB_SRVTAB "" #endif + #ifdef EXEC_BACKEND + #define CONFIG_EXEC_PARAMS "global/config_exec_params" + #endif /* XXX these should appear in other modules' header files */ extern bool Log_connections; *************** *** 2801,2806 **** --- 2804,3007 ---- } + #ifdef EXEC_BACKEND + /* + * This routine dumps out all non-default GUC options into a binary + * file that is read by all exec'ed backends. The format is: + * + * variable name, string, null terminated + * variable value, string, null terminated + * variable source, integer + */ + void + write_nondefault_variables(GucContext context) + { + int i; + char *new_filename, *filename; + int elevel; + FILE *fp; + + Assert(context == PGC_POSTMASTER || context == PGC_SIGHUP); + Assert(DataDir); + elevel = (context == PGC_SIGHUP) ? DEBUG3 : ERROR; + + /* + * Open file + */ + new_filename = malloc(strlen(DataDir) + strlen(CONFIG_EXEC_PARAMS) + + strlen(".new") + 2); + filename = malloc(strlen(DataDir) + strlen(CONFIG_EXEC_PARAMS) + 2); + if (new_filename == NULL || filename == NULL) + { + elog(elevel, "out of memory"); + return; + } + sprintf(new_filename, "%s/" CONFIG_EXEC_PARAMS ".new", DataDir); + sprintf(filename, "%s/" CONFIG_EXEC_PARAMS, DataDir); + + fp = AllocateFile(new_filename, "w"); + if (!fp) + { + free(new_filename); + free(filename); + elog(elevel, "could not write exec config params file `" + CONFIG_EXEC_PARAMS "': %s", strerror(errno)); + return; + } + + for (i = 0; i < num_guc_variables; i++) + { + struct config_generic *gconf = guc_variables[i]; + + if (gconf->source != PGC_S_DEFAULT) + { + fprintf(fp, "%s", gconf->name); + fputc(0, fp); + + switch (gconf->vartype) + { + case PGC_BOOL: + { + struct config_bool *conf = (struct config_bool *) gconf; + + if (*conf->variable == 0) + fprintf(fp, "false"); + else + fprintf(fp, "true"); + } + break; + + case PGC_INT: + { + struct config_int *conf = (struct config_int *) gconf; + + fprintf(fp, "%d", *conf->variable); + } + break; + + case PGC_REAL: + { + struct config_real *conf = (struct config_real *) gconf; + + /* Could lose precision here? */ + fprintf(fp, "%f", *conf->variable); + } + break; + + case PGC_STRING: + { + struct config_string *conf = (struct config_string *) gconf; + + fprintf(fp, "%s", *conf->variable); + } + break; + } + + fputc(0, fp); + + fwrite(&gconf->source, sizeof(gconf->source), 1, fp); + } + } + + FreeFile(fp); + /* Put new file in place, this could delay on Win32 */ + rename(new_filename, filename); + free(new_filename); + free(filename); + return; + } + + + /* + * Read string, including null byte from file + * + * Return NULL on EOF and nothing read + */ + static char * + read_string_with_null(FILE *fp) + { + int i = 0, ch, maxlen = 256; + char *str = NULL; + + do + { + if ((ch = fgetc(fp)) == EOF) + { + if (i == 0) + return NULL; + else + elog(FATAL, "Invalid format of exec config params file"); + } + if (i == 0) + str = malloc(maxlen); + else if (i == maxlen) + str = realloc(str, maxlen *= 2); + str[i++] = ch; + } while (ch != 0); + + return str; + } + + + /* + * This routine loads a previous postmaster dump of its non-default + * settings. + */ + void + read_nondefault_variables(void) + { + char *filename; + FILE *fp; + char *varname, *varvalue; + int varsource; + + Assert(DataDir); + + /* + * Open file + */ + filename = malloc(strlen(DataDir) + strlen(CONFIG_EXEC_PARAMS) + 2); + if (filename == NULL) + { + elog(ERROR, "out of memory"); + return; + } + sprintf(filename, "%s/" CONFIG_EXEC_PARAMS, DataDir); + + fp = AllocateFile(filename, "r"); + if (!fp) + { + free(filename); + /* File not found is fine */ + if (errno != ENOENT) + elog(FATAL, "could not read exec config params file `" + CONFIG_EXEC_PARAMS "': %s", strerror(errno)); + return; + } + + while (1) + { + if ((varname = read_string_with_null(fp)) == NULL) + break; + + if ((varvalue = read_string_with_null(fp)) == NULL) + elog(FATAL, "Invalid format of exec config params file"); + if (fread(&varsource, sizeof(varsource), 1, fp) == 0) + elog(FATAL, "Invalid format of exec config params file"); + + (void) set_config_option(varname, varvalue, PGC_POSTMASTER, + varsource, false, true); + free(varname); + free(varvalue); + } + + FreeFile(fp); + free(filename); + return; + } + #endif + + /* * A little "long argument" simulation, although not quite GNU * compliant. Takes a string of the form "some-option=some value" and *************** *** 3203,3205 **** --- 3404,3407 ---- #include "guc-file.c" + Index: src/include/utils/guc.h =================================================================== RCS file: /cvsroot/pgsql-server/src/include/utils/guc.h,v retrieving revision 1.27 diff -c -c -r1.27 guc.h *** src/include/utils/guc.h 25 Apr 2003 19:45:09 -0000 1.27 --- src/include/utils/guc.h 1 May 2003 19:54:01 -0000 *************** *** 135,138 **** --- 135,143 ---- extern ArrayType *GUCArrayAdd(ArrayType *array, const char *name, const char *value); extern ArrayType *GUCArrayDelete(ArrayType *array, const char *name); + #ifdef EXEC_BACKEND + void write_nondefault_variables(GucContext context); + void read_nondefault_variables(void); + #endif + #endif /* GUC_H */