Dump/read non-default GUC values for use by exec'ed backend, for Win32.
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.318 2003/05/02 22:01:51 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.319 2003/05/02 22:02:47 momjian Exp $
*
* NOTES
*
static void CleanupProc(int pid, int exitstatus);
static void LogChildExit(int lev, const char *procname,
int pid, int exitstatus);
-static int DoBackend(Port *port);
+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);
SetDataDir(potential_DataDir);
ProcessConfigFile(PGC_POSTMASTER);
+#ifdef EXEC_BACKEND
+ write_nondefault_variables(PGC_POSTMASTER);
+#endif
/*
* Check for invalid combinations of GUC settings.
* 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
+ * 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.
*/
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();
}
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);
- }
+ BackendFork(port, bn); /* never returns */
/* in parent, error */
if (pid < 0)
}
+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
}
/*
- * DoBackend -- perform authentication, and if successful, set up the
+ * 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;
* If PostgresMain() fails, return status.
*/
static int
-DoBackend(Port *port)
+BackendFinalize(Port *port)
{
char *remote_host;
char **av;
/* 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
unsigned short remote_port;
char *host_addr;
#ifdef HAVE_IPV6
- char ip_hostinfo[INET6_ADDRSTRLEN];
+ char ip_hostinfo[INET6_ADDRSTRLEN];
#else
char ip_hostinfo[INET_ADDRSTRLEN];
#endif
}
else
{
- /* not AF_INET */
+ /* not AF_INET */
remote_host = "[local]";
if (Log_connections)
* 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");
+ elog(FATAL, "BackendFinalize: Unable to set timer for auth timeout");
/*
* Receive the startup packet (which might turn out to be a cancel
* SIGTERM/SIGQUIT again until backend startup is complete.
*/
if (!disable_sig_alarm(false))
- elog(FATAL, "DoBackend: Unable to disable timer for auth timeout");
+ elog(FATAL, "BackendFinalize: Unable to disable timer for auth timeout");
PG_SETMASK(&BlockSig);
if (Log_connections)
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.121 2003/05/02 22:01:51 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.122 2003/05/02 22:02:47 momjian Exp $
*
*--------------------------------------------------------------------
*/
#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;
}
+#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
#include "guc-file.c"
+
* Copyright 2000-2003 by PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
- * $Id: guc.h,v 1.29 2003/05/02 22:01:51 momjian Exp $
+ * $Id: guc.h,v 1.30 2003/05/02 22:02:47 momjian Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
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 */