* - Add some automatic call for pgstat vacuuming.
*
* - Add a pgstat config column to pg_database, so this
- * entire thing can be enabled/disabled on a per db base.
+ * entire thing can be enabled/disabled on a per db basis.
*
* Copyright (c) 2001-2003, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.71 2004/05/24 02:47:47 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.72 2004/05/28 05:12:58 tgl Exp $
* ----------
*/
#include "postgres.h"
#include "utils/ps_status.h"
#include "utils/syscache.h"
-#ifdef EXEC_BACKEND
-#include "utils/guc.h"
-#endif
-
-#ifdef WIN32
-extern pid_t win32_forkexec(const char* path, char *argv[]);
-#endif
/* ----------
* GUC parameters
static PgStat_StatBeEntry *pgStatBeTable = NULL;
static int pgStatNumBackends = 0;
-static char pgStat_tmpfname[MAXPGPATH];
static char pgStat_fname[MAXPGPATH];
+static char pgStat_tmpfname[MAXPGPATH];
/* ----------
* ----------
*/
#ifdef EXEC_BACKEND
+
+typedef enum STATS_PROCESS_TYPE
+{
+ STAT_PROC_BUFFER,
+ STAT_PROC_COLLECTOR
+} STATS_PROCESS_TYPE;
+
static pid_t pgstat_forkexec(STATS_PROCESS_TYPE procType);
-static void pgstat_parseArgs(PGSTAT_FORK_ARGS);
+static void pgstat_parseArgs(int argc, char *argv[]);
+
#endif
-NON_EXEC_STATIC void pgstat_main(PGSTAT_FORK_ARGS);
-NON_EXEC_STATIC void pgstat_mainChild(PGSTAT_FORK_ARGS);
-static void pgstat_mainInit(void);
+
+NON_EXEC_STATIC void PgstatBufferMain(int argc, char *argv[]);
+NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]);
static void pgstat_recvbuffer(void);
static void pgstat_die(SIGNAL_ARGS);
* ------------------------------------------------------------
*/
-#ifdef EXEC_BACKEND
-
-void
-pgstat_init_forkexec_backend(void)
-{
- Assert(DataDir != NULL);
- snprintf(pgStat_fname, MAXPGPATH,
- PGSTAT_STAT_FILENAME, DataDir);
-}
-
-#endif
-
/* ----------
* pgstat_init() -
*
pgstat_collect_startcollector = true;
/*
- * Initialize the filenames for the status reports.
+ * Initialize the filename for the status reports. (In the EXEC_BACKEND
+ * case, this only sets the value in the postmaster. The collector
+ * subprocess will recompute the value for itself, and individual
+ * backends must do so also if they want to access the file.)
*/
- snprintf(pgStat_tmpfname, MAXPGPATH,
- PGSTAT_STAT_TMPFILE, DataDir, getpid());
- snprintf(pgStat_fname, MAXPGPATH,
- PGSTAT_STAT_FILENAME, DataDir);
+ snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
/*
* If we don't have to start a collector or should reset the collected
#ifdef EXEC_BACKEND
-/* ----------
+/*
* pgstat_forkexec() -
*
- * Used to format up the arglist for, then fork and exec, statistics
+ * Format up the arglist for, then fork and exec, statistics
* (buffer and collector) processes
- *
*/
static pid_t
pgstat_forkexec(STATS_PROCESS_TYPE procType)
{
- pid_t pid;
- char *av[15];
+ char *av[12];
int ac = 0, bufc = 0, i;
- char pgstatBuf[12][MAXPGPATH];
+ char pgstatBuf[7][32];
av[ac++] = "postgres";
+
switch (procType)
{
case STAT_PROC_BUFFER:
- av[ac++] = "-statBuf";
+ av[ac++] = "-forkbuf";
break;
case STAT_PROC_COLLECTOR:
- av[ac++] = "-statCol";
+ av[ac++] = "-forkcol";
break;
default:
Assert(false);
}
- /* Sockets + pipes */
- bufc = 0;
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatSock);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[0]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPmPipe[1]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[0]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatCollectorPmPipe[1]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[0]);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",pgStatPipe[1]);
-
- /* + misc */
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"%d",MaxBackends);
-
- /* + the pstat file names, and postgres pathname */
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",pgStat_tmpfname);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",pgStat_fname);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",postgres_exec_path);
- snprintf(pgstatBuf[bufc++],MAXPGPATH,"\"%s\"",DataDir);
+ av[ac++] = NULL; /* filled in by postmaster_forkexec */
+
+ /* postgres_exec_path is not passed by write_backend_variables */
+ av[ac++] = postgres_exec_path;
+
+ /* Sockets + pipes (those not passed by write_backend_variables) */
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[0]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[1]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[0]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[1]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[0]);
+ snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[1]);
/* Add to the arg list */
Assert(bufc <= lengthof(pgstatBuf));
for (i = 0; i < bufc; i++)
av[ac++] = pgstatBuf[i];
- av[ac++] = NULL;
- Assert(ac <= lengthof(av));
+ av[ac] = NULL;
+ Assert(ac < lengthof(av));
- /* Fire off execv in child */
-#ifdef WIN32
- pid = win32_forkexec(postgres_exec_path, av);
-#else
- if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
- /* FIXME: [fork/exec] suggestions for what to do here? Can't call elog... */
- abort();
-#endif
- return pid; /* Parent returns pid */
+ return postmaster_forkexec(ac, av);
}
-/* ----------
+/*
* pgstat_parseArgs() -
*
- * Used to unformat the arglist for exec'ed statistics
+ * Extract data from the arglist for exec'ed statistics
* (buffer and collector) processes
- *
*/
static void
-pgstat_parseArgs(PGSTAT_FORK_ARGS)
+pgstat_parseArgs(int argc, char *argv[])
{
- Assert(argc == 14);
-
- if (find_my_exec(argv[0], my_exec_path) < 0)
- elog(FATAL,
- gettext("%s: could not locate my own executable path"),
- argv[0]);
-
- get_pkglib_path(my_exec_path, pkglib_path);
+ Assert(argc == 10);
- argc = 2;
- pgStatSock = atoi(argv[argc++]);
+ argc = 3;
+ StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH);
pgStatPmPipe[0] = atoi(argv[argc++]);
pgStatPmPipe[1] = atoi(argv[argc++]);
pgStatCollectorPmPipe[0] = atoi(argv[argc++]);
pgStatCollectorPmPipe[1] = atoi(argv[argc++]);
pgStatPipe[0] = atoi(argv[argc++]);
pgStatPipe[1] = atoi(argv[argc++]);
- MaxBackends = atoi(argv[argc++]);
- StrNCpy(pgStat_tmpfname,argv[argc++],MAXPGPATH);
- StrNCpy(pgStat_fname, argv[argc++],MAXPGPATH);
- StrNCpy(postgres_exec_path, argv[argc++],MAXPGPATH);
- DataDir = strdup(argv[argc++]);
-
- read_nondefault_variables();
}
-#endif
+#endif /* EXEC_BACKEND */
+
/* ----------
* pgstat_start() -
/* Drop our connection to postmaster's shared memory, as well */
PGSharedMemoryDetach();
- pgstat_main();
+ PgstatBufferMain(0, NULL);
break;
#endif
}
-/* ------------------------------------------------------------
- * Local functions implementing the statistics collector itself follow
- *------------------------------------------------------------
+/* ----------
+ * PgstatBufferMain() -
+ *
+ * Start up the statistics buffer process. This is the body of the
+ * postmaster child process.
+ *
+ * The argc/argv parameters are valid only in EXEC_BACKEND case.
+ * ----------
*/
-
-static void
-pgstat_mainInit(void)
+NON_EXEC_STATIC void
+PgstatBufferMain(int argc, char *argv[])
{
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
-#ifdef EXEC_BACKEND
- /* In EXEC case we will not have inherited these settings */
- IsPostmasterEnvironment = true;
- whereToSendOutput = None;
-
- /* Setup global context */
- MemoryContextInit(); /* before any elog'ing can occur */
- InitializeGUCOptions();
-#endif
-
MyProcPid = getpid(); /* reset MyProcPid */
/* Lose the postmaster's on-exit routines */
pqsignal(SIGTTOU, SIG_DFL);
pqsignal(SIGCONT, SIG_DFL);
pqsignal(SIGWINCH, SIG_DFL);
-}
-
+ /* unblock will happen in pgstat_recvbuffer */
-/* ----------
- * pgstat_main() -
- *
- * Start up the statistics collector itself. This is the body of the
- * postmaster child process.
- * ----------
- */
-NON_EXEC_STATIC void
-pgstat_main(PGSTAT_FORK_ARGS)
-{
- pgstat_mainInit(); /* Note: for *both* EXEC_BACKEND and regular cases */
#ifdef EXEC_BACKEND
pgstat_parseArgs(argc,argv);
#endif
#ifndef EXEC_BACKEND
case 0:
/* child becomes collector process */
- pgstat_mainChild();
+ PgstatCollectorMain(0, NULL);
break;
#endif
}
+/* ----------
+ * PgstatCollectorMain() -
+ *
+ * Start up the statistics collector itself. This is the body of the
+ * postmaster grandchild process.
+ *
+ * The argc/argv parameters are valid only in EXEC_BACKEND case.
+ * ----------
+ */
NON_EXEC_STATIC void
-pgstat_mainChild(PGSTAT_FORK_ARGS)
+PgstatCollectorMain(int argc, char *argv[])
{
PgStat_Msg msg;
fd_set rfds;
bool need_statwrite;
HASHCTL hash_ctl;
+ MyProcPid = getpid(); /* reset MyProcPid */
+
+ /*
+ * Reset signal handling. With the exception of restoring default
+ * SIGCHLD handling, this is a no-op in the non-EXEC_BACKEND case
+ * because we'll have inherited these settings from the buffer process;
+ * but it's not a no-op for EXEC_BACKEND.
+ */
+ pqsignal(SIGHUP, SIG_IGN);
+ pqsignal(SIGINT, SIG_IGN);
+ pqsignal(SIGTERM, SIG_IGN);
+ pqsignal(SIGQUIT, SIG_IGN);
+ pqsignal(SIGALRM, SIG_IGN);
+ pqsignal(SIGPIPE, SIG_IGN);
+ pqsignal(SIGUSR1, SIG_IGN);
+ pqsignal(SIGUSR2, SIG_IGN);
+ pqsignal(SIGCHLD, SIG_DFL);
+ pqsignal(SIGTTIN, SIG_DFL);
+ pqsignal(SIGTTOU, SIG_DFL);
+ pqsignal(SIGCONT, SIG_DFL);
+ pqsignal(SIGWINCH, SIG_DFL);
+ PG_SETMASK(&UnBlockSig);
+
#ifdef EXEC_BACKEND
- pgstat_mainInit(); /* Note: only in EXEC_BACKEND case */
pgstat_parseArgs(argc,argv);
-#else
- MyProcPid = getpid(); /* reset MyProcPid */
#endif
+ /* Close unwanted files */
closesocket(pgStatPipe[1]);
closesocket(pgStatSock);
pmPipe = pgStatCollectorPmPipe[0];
- /*
- * In the child we can have default SIGCHLD handling (in case we want
- * to call system() here...)
- */
- pqsignal(SIGCHLD, SIG_DFL);
-
/*
* Identify myself via ps
*/
init_ps_display("stats collector process", "", "");
set_ps_display("");
+ /*
+ * Initialize filenames needed for status reports.
+ */
+ snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
+ /* tmpfname need only be set correctly in this process */
+ snprintf(pgStat_tmpfname, MAXPGPATH, PGSTAT_STAT_TMPFILE,
+ DataDir, getpid());
+
/*
* Arrange to write the initial status file right away
*/
if (betab != NULL)
*betab = NULL;
+ /*
+ * In EXEC_BACKEND case, we won't have inherited pgStat_fname from
+ * postmaster, so compute it first time through.
+ */
+#ifdef EXEC_BACKEND
+ if (pgStat_fname[0] == '\0')
+ {
+ Assert(DataDir != NULL);
+ snprintf(pgStat_fname, MAXPGPATH, PGSTAT_STAT_FILENAME, DataDir);
+ }
+#endif
+
/*
* Try to open the status file. If it doesn't exist, the backends
* simply return zero for anything and the collector simply starts
* message to setup a backend process.
*
* The postmaster also manages system-wide operations such as
- * startup, shutdown, and periodic checkpoints. The postmaster
- * itself doesn't do those operations, mind you --- it just forks
- * off a subprocess to do them at the right times. It also takes
- * care of resetting the system if a backend crashes.
+ * startup and shutdown. The postmaster itself doesn't do those
+ * operations, mind you --- it just forks off a subprocess to do them
+ * at the right times. It also takes care of resetting the system
+ * if a backend crashes.
*
* The postmaster process creates the shared memory and semaphore
* pools during startup, but as a rule does not touch them itself.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.397 2004/05/27 17:12:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.398 2004/05/28 05:12:58 tgl Exp $
*
* NOTES
*
#include "pgstat.h"
-#define INVALID_SOCK (-1)
-
#ifdef HAVE_SIGPROCMASK
sigset_t UnBlockSig,
BlockSig,
#define MAXLISTEN 10
static int ListenSocket[MAXLISTEN];
-/* Used to reduce macros tests */
-#ifdef EXEC_BACKEND
-const bool ExecBackend = true;
-
-#else
-const bool ExecBackend = false;
-#endif
-
/*
* Set by the -o option
*/
/*
* postmaster.c - function prototypes
*/
-static void pmdaemonize(int argc, char *argv[]);
+static void checkDataDir(const char *checkdir);
+#ifdef USE_RENDEZVOUS
+static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode,
+ void *context);
+#endif
+static void pmdaemonize(void);
static Port *ConnCreate(int serverFd);
static void ConnFree(Port *port);
static void reset_shared(unsigned short port);
static void CleanupProc(int pid, int exitstatus);
static void LogChildExit(int lev, const char *procname,
int pid, int exitstatus);
-static void BackendInit(Port *port);
static int BackendRun(Port *port);
static void ExitPostmaster(int status);
static void usage(const char *);
static void SignalChildren(int signal);
static int CountChildren(void);
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
-NON_EXEC_STATIC void SSDataBaseInit(int xlop);
static pid_t SSDataBase(int xlop);
static void
postmaster_error(const char *fmt,...)
#ifdef EXEC_BACKEND
#ifdef WIN32
-pid_t win32_forkexec(const char *path, char *argv[]);
-
+static pid_t win32_forkexec(const char *path, char *argv[]);
static void win32_AddChild(pid_t pid, HANDLE handle);
static void win32_RemoveChild(pid_t pid);
static pid_t win32_waitpid(int *exitstatus);
static unsigned long win32_numChildren = 0;
#endif
-static pid_t Backend_forkexec(Port *port);
+static pid_t backend_forkexec(Port *port);
+static pid_t internal_forkexec(int argc, char *argv[], Port *port);
-static unsigned long tmpBackendFileNum = 0;
-void read_backend_variables(unsigned long id, Port *port);
-static bool write_backend_variables(Port *port);
+static void read_backend_variables(char *filename, Port *port);
+static bool write_backend_variables(char *filename, Port *port);
static void ShmemBackendArrayAdd(Backend *bn);
static void ShmemBackendArrayRemove(pid_t pid);
-#endif
+
+#endif /* EXEC_BACKEND */
#define StartupDataBase() SSDataBase(BS_XLOG_STARTUP)
#define CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT)
#define StartBackgroundWriter() SSDataBase(BS_XLOG_BGWRITER)
#define ShutdownDataBase() SSDataBase(BS_XLOG_SHUTDOWN)
-static void
-checkDataDir(const char *checkdir)
-{
- char path[MAXPGPATH];
- FILE *fp;
- struct stat stat_buf;
-
- if (checkdir == NULL)
- {
- fprintf(stderr,
- gettext("%s does not know where to find the database system data.\n"
- "You must specify the directory that contains the database system\n"
- "either by specifying the -D invocation option or by setting the\n"
- "PGDATA environment variable.\n"),
- progname);
- ExitPostmaster(2);
- }
-
- if (stat(checkdir, &stat_buf) == -1)
- {
- if (errno == ENOENT)
- ereport(FATAL,
- (errcode_for_file_access(),
- errmsg("data directory \"%s\" does not exist",
- checkdir)));
- else
- ereport(FATAL,
- (errcode_for_file_access(),
- errmsg("could not read permissions of directory \"%s\": %m",
- checkdir)));
- }
-
- /*
- * Check if the directory has group or world access. If so, reject.
- *
- * XXX temporarily suppress check when on Windows, because there may not
- * be proper support for Unix-y file permissions. Need to think of a
- * reasonable check to apply on Windows.
- */
-#if !defined(__CYGWIN__) && !defined(WIN32)
- if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
- ereport(FATAL,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("data directory \"%s\" has group or world access",
- checkdir),
- errdetail("Permissions should be u=rwx (0700).")));
-#endif
-
- /* Look for PG_VERSION before looking for pg_control */
- ValidatePgVersion(checkdir);
-
- snprintf(path, sizeof(path), "%s/global/pg_control", checkdir);
-
- fp = AllocateFile(path, PG_BINARY_R);
- if (fp == NULL)
- {
- fprintf(stderr,
- gettext("%s: could not find the database system\n"
- "Expected to find it in the directory \"%s\",\n"
- "but could not open file \"%s\": %s\n"),
- progname, checkdir, path, strerror(errno));
- ExitPostmaster(2);
- }
- FreeFile(fp);
-}
-
-
-#ifdef USE_RENDEZVOUS
-
-/* reg_reply -- empty callback function for DNSServiceRegistrationCreate() */
-static void
-reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
-{
-
-}
-#endif
+/*
+ * Postmaster main entry point
+ */
int
PostmasterMain(int argc, char *argv[])
{
IgnoreSystemIndexes(false);
if (find_my_exec(argv[0], my_exec_path) < 0)
- elog(FATAL,
- gettext("%s: could not locate my own executable path"),
+ elog(FATAL, "%s: could not locate my own executable path",
argv[0]);
get_pkglib_path(my_exec_path, pkglib_path);
}
#ifdef EXEC_BACKEND
- if (find_other_exec(argv[0], "postgres", PG_VERSIONSTR, postgres_exec_path) < 0)
+ if (find_other_exec(argv[0], "postgres", PG_VERSIONSTR,
+ postgres_exec_path) < 0)
ereport(FATAL,
- (errmsg("%s: could not locate postgres executable or non-matching version",
+ (errmsg("%s: could not locate matching postgres executable",
progname)));
#endif
* will show the wrong PID.
*/
if (SilentMode)
- pmdaemonize(argc, argv);
+ pmdaemonize();
/*
* Create lockfile for data directory.
return 0; /* not reached */
}
+
+/*
+ * Validate the proposed data directory
+ */
+static void
+checkDataDir(const char *checkdir)
+{
+ char path[MAXPGPATH];
+ FILE *fp;
+ struct stat stat_buf;
+
+ if (checkdir == NULL)
+ {
+ fprintf(stderr,
+ gettext("%s does not know where to find the database system data.\n"
+ "You must specify the directory that contains the database system\n"
+ "either by specifying the -D invocation option or by setting the\n"
+ "PGDATA environment variable.\n"),
+ progname);
+ ExitPostmaster(2);
+ }
+
+ if (stat(checkdir, &stat_buf) == -1)
+ {
+ if (errno == ENOENT)
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("data directory \"%s\" does not exist",
+ checkdir)));
+ else
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg("could not read permissions of directory \"%s\": %m",
+ checkdir)));
+ }
+
+ /*
+ * Check if the directory has group or world access. If so, reject.
+ *
+ * XXX temporarily suppress check when on Windows, because there may not
+ * be proper support for Unix-y file permissions. Need to think of a
+ * reasonable check to apply on Windows.
+ */
+#if !defined(__CYGWIN__) && !defined(WIN32)
+ if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
+ ereport(FATAL,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("data directory \"%s\" has group or world access",
+ checkdir),
+ errdetail("Permissions should be u=rwx (0700).")));
+#endif
+
+ /* Look for PG_VERSION before looking for pg_control */
+ ValidatePgVersion(checkdir);
+
+ snprintf(path, sizeof(path), "%s/global/pg_control", checkdir);
+
+ fp = AllocateFile(path, PG_BINARY_R);
+ if (fp == NULL)
+ {
+ fprintf(stderr,
+ gettext("%s: could not find the database system\n"
+ "Expected to find it in the directory \"%s\",\n"
+ "but could not open file \"%s\": %s\n"),
+ progname, checkdir, path, strerror(errno));
+ ExitPostmaster(2);
+ }
+ FreeFile(fp);
+}
+
+
+#ifdef USE_RENDEZVOUS
+
+/*
+ * empty callback function for DNSServiceRegistrationCreate()
+ */
+static void
+reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
+{
+
+}
+
+#endif /* USE_RENDEZVOUS */
+
+
+/*
+ * Fork away from the controlling terminal (-S option)
+ */
static void
-pmdaemonize(int argc, char *argv[])
+pmdaemonize(void)
{
#ifdef WIN32
/* not supported */
#endif
#ifdef LINUX_PROFILE
- /* see comments in BackendRun */
+ /* see comments in BackendStartup */
getitimer(ITIMER_PROF, &prof_itimer);
#endif
}
-
/*
* Print out help message
*/
"Report bugs to <pgsql-bugs@postgresql.org>.\n"));
}
+
+/*
+ * Main loop of postmaster
+ */
static int
ServerLoop(void)
{
* Initialise the masks for select() for the ports
* we are listening on. Return the number of sockets to listen on.
*/
-
static int
initMasks(fd_set *rmask)
{
int backendPID;
long cancelAuthCode;
Backend *bp;
-
#ifndef EXEC_BACKEND
Dlelem *curr;
-
#else
int i;
#endif
return;
}
- /* See if we have a matching backend */
+ /*
+ * See if we have a matching backend. In the EXEC_BACKEND case, we
+ * can no longer access the postmaster's own backend list, and must
+ * rely on the backup array in shared memory.
+ */
#ifndef EXEC_BACKEND
for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
{
ereport(LOG,
(errmsg("received SIGHUP, reloading configuration files")));
ProcessConfigFile(PGC_SIGHUP);
-#ifdef EXEC_BACKEND
- write_nondefault_variables(PGC_SIGHUP);
-#endif
SignalChildren(SIGHUP);
load_hba();
load_ident();
+#ifdef EXEC_BACKEND
+ /* Update the starting-point file for future children */
+ write_nondefault_variables(PGC_SIGHUP);
+#endif
+
/*
* Tell the background writer to terminate so that we will start a
* new one with a possibly changed config
}
-
/*
* pmdie -- signal handler for processing various postmaster signals.
*/
return STATUS_ERROR;
}
+ /* Pass down canAcceptConnections state (kluge for EXEC_BACKEND case) */
+ port->canAcceptConnections = canAcceptConnections();
+
/*
* Flush stdio channels just before fork, to avoid double-output
* problems. Ideally we'd use fflush(NULL) here, but there are still a
fflush(stdout);
fflush(stderr);
+#ifdef EXEC_BACKEND
+
+ pid = backend_forkexec(port);
+
+#else /* !EXEC_BACKEND */
+
#ifdef LINUX_PROFILE
/*
beos_before_backend_startup();
#endif
- port->canAcceptConnections = canAcceptConnections();
-#ifdef EXEC_BACKEND
- pid = Backend_forkexec(port);
-#else
pid = fork();
if (pid == 0) /* child */
proc_exit(BackendRun(port));
}
-#endif
- /* in parent, error */
+#endif /* EXEC_BACKEND */
+
if (pid < 0)
{
+ /* in parent, fork failed */
int save_errno = errno;
#ifdef __BEOS__
return STATUS_ERROR;
}
- /* in parent, normal */
+ /* in parent, successful fork */
ereport(DEBUG2,
(errmsg_internal("forked new backend, pid=%d socket=%d",
(int) pid, port->sock)));
/*
- * BackendInit/Run -- perform authentication [BackendInit], and if successful,
- * set up the backend's argument list [BackendRun] and invoke
- * backend main()
+ * BackendRun -- perform authentication, and if successful,
+ * set up the backend's argument list and invoke PostgresMain()
*
* returns:
* Shouldn't return at all.
* If PostgresMain() fails, return status.
*/
-static void
-BackendInit(Port *port)
+static int
+BackendRun(Port *port)
{
int status;
struct timeval now;
char remote_host[NI_MAXHOST];
char remote_port[NI_MAXSERV];
char remote_ps_data[NI_MAXHOST];
+ char **av;
+ int maxac;
+ int ac;
+ char debugbuf[32];
+ char protobuf[32];
+ int i;
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
- ClientAuthInProgress = true; /* limit visibility of log messages */
+ /*
+ * Let's clean up ourselves as the postmaster child, and close the
+ * postmaster's other sockets
+ */
+ ClosePostmasterPorts(true);
/* We don't want the postmaster's proc_exit() handlers */
on_exit_reset();
* Signal handlers setting is moved to tcop/postgres...
*/
+ /* Save port etc. for ps status */
+ MyProcPort = port;
+
+ /* Reset MyProcPid to new backend's pid */
+ MyProcPid = getpid();
+
+ /*
+ * 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 it is not honored until after authentication.)
+ */
+ if (PreAuthDelay > 0)
+ pg_usleep(PreAuthDelay * 1000000L);
+
+ ClientAuthInProgress = true; /* limit visibility of log messages */
+
/* save start time for end of session reporting */
gettimeofday(&(port->session_start), NULL);
port->remote_port = "";
port->commandTag = "";
- /* Save port etc. for ps status */
- MyProcPort = port;
-
- /* Reset MyProcPid to new backend's pid */
- MyProcPid = getpid();
-
/*
* Initialize libpq and enable reporting of ereport errors to the
* client. Must do this now because authentication uses libpq to send
port->remote_host = strdup(remote_host);
port->remote_port = strdup(remote_port);
+ /*
+ * In EXEC_BACKEND case, we didn't inherit the contents of pg_hba.c
+ * 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);
+
+ load_hba();
+ load_ident();
+ load_user();
+ load_group();
+#endif
+
/*
* Ready to begin client interaction. We will give up and exit(0)
* after a time delay, so that a broken client can't hog a connection
random_seed = 0;
gettimeofday(&now, &tz);
srandom((unsigned int) now.tv_usec);
-}
-
-
-static int
-BackendRun(Port *port)
-{
- char **av;
- int maxac;
- int ac;
- char debugbuf[32];
- char protobuf[32];
- int i;
-
- /*
- * Let's clean up ourselves as the postmaster child, and close the
- * postmaster's other sockets
- */
- ClosePostmasterPorts(true);
-
- /*
- * 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 it is not honored until after authentication.)
- */
- if (PreAuthDelay > 0)
- pg_usleep(PreAuthDelay * 1000000L);
-
- /* Will exit on failure */
- BackendInit(port);
/* ----------------
/*
* Pass any backend switches specified with -o in the postmaster's own
- * command line. We assume these are secure.
+ * 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);
snprintf(protobuf, sizeof(protobuf), "-v%u", port->proto);
av[ac++] = protobuf;
-#ifdef EXEC_BACKEND
- /* pass data dir before end of secure switches (-p) */
- av[ac++] = "-D";
- av[ac++] = DataDir;
-#endif
-
/*
* Tell the backend it is being called from the postmaster, and which
* database to use. -p marks the end of secure switches.
* username isn't lost either; see ProcessStartupPacket().
*/
MemoryContextSwitchTo(TopMemoryContext);
-#ifndef EXEC_BACKEND
MemoryContextDelete(PostmasterContext);
-#endif
PostmasterContext = NULL;
/*
#ifdef EXEC_BACKEND
-
/*
- * SubPostmasterMain -- prepare the fork/exec'd process to be in an equivalent
- * state (for calling BackendRun) as a forked process.
+ * postmaster_forkexec -- fork and exec a postmaster subprocess
*
- * returns:
- * Shouldn't return at all.
+ * The caller must have set up the argv array already, except for argv[2]
+ * which will be filled with the name of the temp variable file.
+ *
+ * Returns the child process PID, or -1 on fork failure (a suitable error
+ * message has been logged on failure).
+ *
+ * All uses of this routine will dispatch to SubPostmasterMain in the
+ * child process.
*/
-void
-SubPostmasterMain(int argc, char *argv[])
+pid_t
+postmaster_forkexec(int argc, char *argv[])
{
- unsigned long backendID;
Port port;
- memset((void *) &port, 0, sizeof(Port));
- Assert(argc == 2);
+ /* This entry point passes dummy values for the Port variables */
+ memset(&port, 0, sizeof(port));
+ return internal_forkexec(argc, argv, &port);
+}
- /* Do this sooner rather than later... */
- IsUnderPostmaster = true; /* we are a postmaster subprocess now */
+/*
+ * backend_forkexec -- fork/exec off a backend process
+ *
+ * returns the pid of the fork/exec'd process, or -1 on failure
+ */
+static pid_t
+backend_forkexec(Port *port)
+{
+ char *av[4];
+ int ac = 0;
- /* In EXEC case we will not have inherited these settings */
- IsPostmasterEnvironment = true;
- whereToSendOutput = None;
+ av[ac++] = "postgres";
+ av[ac++] = "-forkbackend";
+ av[ac++] = NULL; /* filled in by internal_forkexec */
- /* Setup global context */
- MemoryContextInit();
- InitializeGUCOptions();
+ av[ac] = NULL;
+ Assert(ac < lengthof(av));
- /* Parse passed-in context */
- argc = 0;
- backendID = (unsigned long) atol(argv[argc++]);
- DataDir = strdup(argv[argc++]);
+ return internal_forkexec(ac, av, port);
+}
- /* Read in file-based context */
- read_backend_variables(backendID, &port);
- read_nondefault_variables();
+static pid_t
+internal_forkexec(int argc, char *argv[], Port *port)
+{
+ pid_t pid;
+ char tmpfilename[MAXPGPATH];
- /* Remaining initialization */
- pgstat_init_forkexec_backend();
+ if (!write_backend_variables(tmpfilename, port))
+ return -1; /* log made by write_backend_variables */
- /* FIXME: [fork/exec] Ugh */
- load_hba();
- load_ident();
- load_user();
- load_group();
+ /* Make sure caller set up argv properly */
+ Assert(argc >= 3);
+ Assert(argv[argc] == NULL);
+ Assert(strncmp(argv[1], "-fork", 5) == 0);
+ Assert(argv[2] == NULL);
- /* Attach process to shared segments */
- CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+ /* Insert temp file name after -fork argument */
+ argv[2] = tmpfilename;
- /* Run backend */
- proc_exit(BackendRun(&port));
-}
+#ifdef WIN32
+ pid = win32_forkexec(postgres_exec_path, argv);
+#else
+ /* Fire off execv in child */
+ if ((pid = fork()) == 0)
+ {
+ if (execv(postgres_exec_path, argv) < 0)
+ {
+ ereport(LOG,
+ (errmsg("could not exec backend process \"%s\": %m",
+ postgres_exec_path)));
+ /* We're already in the child process here, can't return */
+ exit(1);
+ }
+ }
+#endif
+ return pid; /* Parent returns pid, or -1 on fork failure */
+}
/*
- * Backend_forkexec -- fork/exec off a backend process
+ * SubPostmasterMain -- Get the fork/exec'd process into a state equivalent
+ * to what it would be if we'd simply forked on Unix, and then
+ * dispatch to the appropriate place.
*
- * returns:
- * the pid of the fork/exec'd process
+ * The first two command line arguments are expected to be "-forkFOO"
+ * (where FOO indicates which postmaster child we are to become), and
+ * the name of a variables file that we can read to load data that would
+ * have been inherited by fork() on Unix. Remaining arguments go to the
+ * subprocess FooMain() routine.
*/
-static pid_t
-Backend_forkexec(Port *port)
+int
+SubPostmasterMain(int argc, char *argv[])
{
- pid_t pid;
- char *av[5];
- int ac = 0,
- bufc = 0,
- i;
- char buf[2][MAXPGPATH];
+ Port port;
- if (!write_backend_variables(port))
- return -1; /* log made by write_backend_variables */
+ /* Do this sooner rather than later... */
+ IsUnderPostmaster = true; /* we are a postmaster subprocess now */
- av[ac++] = "postgres";
- av[ac++] = "-forkexec";
+ MyProcPid = getpid(); /* reset MyProcPid */
- /* Format up context to pass to exec'd process */
- snprintf(buf[bufc++], MAXPGPATH, "%lu", tmpBackendFileNum);
- snprintf(buf[bufc++], MAXPGPATH, "\"%s\"", DataDir);
+ /* In EXEC_BACKEND case we will not have inherited these settings */
+ IsPostmasterEnvironment = true;
+ whereToSendOutput = None;
+ pqinitmask();
+ PG_SETMASK(&BlockSig);
- /* Add to the arg list */
- Assert(bufc <= lengthof(buf));
- for (i = 0; i < bufc; i++)
- av[ac++] = buf[i];
+ /* Setup essential subsystems */
+ MemoryContextInit();
+ InitializeGUCOptions();
- /* FIXME: [fork/exec] ExtraOptions? */
+ /* Check we got appropriate args */
+ if (argc < 3)
+ elog(FATAL, "invalid subpostmaster invocation");
- av[ac++] = NULL;
- Assert(ac <= lengthof(av));
+ /* Read in file-based context */
+ memset(&port, 0, sizeof(Port));
+ read_backend_variables(argv[2], &port);
+ read_nondefault_variables();
-#ifdef WIN32
- pid = win32_forkexec(postgres_exec_path, av); /* logs on error */
-#else
- /* Fire off execv in child */
- if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
+ /* Run backend or appropriate child */
+ if (strcmp(argv[1], "-forkbackend") == 0)
+ {
+ /* BackendRun will close sockets */
+
+ /* Attach process to shared segments */
+ CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+ Assert(argc == 3); /* shouldn't be any more args */
+ proc_exit(BackendRun(&port));
+ }
+ if (strcmp(argv[1], "-forkboot") == 0)
+ {
+ /* Close the postmaster's sockets */
+ ClosePostmasterPorts(true);
+
+ /* Attach process to shared segments */
+ CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
+
+ BootstrapMain(argc - 2, argv + 2);
+ ExitPostmaster(0);
+ }
+ if (strcmp(argv[1], "-forkbuf") == 0)
+ {
+ /* Close the postmaster's sockets */
+ ClosePostmasterPorts(false);
+
+ /* Do not want to attach to shared memory */
+
+ PgstatBufferMain(argc, argv);
+ ExitPostmaster(0);
+ }
+ if (strcmp(argv[1], "-forkcol") == 0)
+ {
/*
- * FIXME: [fork/exec] suggestions for what to do here? Probably OK
- * to issue error (unlike pgstat case)
+ * Do NOT close postmaster sockets here, because we are forking from
+ * pgstat buffer process, which already did it.
*/
- abort();
-#endif
- return pid; /* Parent returns pid */
+
+ /* Do not want to attach to shared memory */
+
+ PgstatCollectorMain(argc, argv);
+ ExitPostmaster(0);
+ }
+
+ return 1; /* shouldn't get here */
}
-#endif
+
+#endif /* EXEC_BACKEND */
/*
return cnt;
}
+
/*
- * Fire off a subprocess for startup/shutdown/checkpoint/bgwriter.
+ * SSDataBase -- start a non-backend child process for the postmaster
*
- * Return value of SSDataBase is subprocess' PID, or 0 if failed to start subprocess
- * (0 is returned only for checkpoint/bgwriter cases).
+ * xlog determines what kind of child will be started. All child types
+ * initially go to BootstrapMain, which will handle common setup.
*
- * note: in the EXEC_BACKEND case, we delay the fork until argument list has been
- * established
+ * Return value of SSDataBase is subprocess' PID, or 0 if failed to start
+ * subprocess (0 is returned only for checkpoint/bgwriter cases).
*/
-NON_EXEC_STATIC void
-SSDataBaseInit(int xlop)
+static pid_t
+SSDataBase(int xlop)
{
- const char *statmsg;
+ Backend *bn;
+ pid_t pid;
+ char *av[10];
+ int ac = 0;
+ char xlbuf[32];
+#ifdef LINUX_PROFILE
+ struct itimerval prof_itimer;
+#endif
- IsUnderPostmaster = true; /* we are a postmaster subprocess now */
+ /*
+ * Set up command-line arguments for subprocess
+ */
+ av[ac++] = "postgres";
#ifdef EXEC_BACKEND
- /* In EXEC case we will not have inherited these settings */
- IsPostmasterEnvironment = true;
- whereToSendOutput = None;
+ av[ac++] = "-forkboot";
+ av[ac++] = NULL; /* filled in by postmaster_forkexec */
#endif
- MyProcPid = getpid(); /* reset MyProcPid */
+ snprintf(xlbuf, sizeof(xlbuf), "-x%d", xlop);
+ av[ac++] = xlbuf;
- /* Lose the postmaster's on-exit routines and port connections */
- on_exit_reset();
+ av[ac++] = "-p";
+ av[ac++] = "template1";
+
+ av[ac] = NULL;
+ Assert(ac < lengthof(av));
/*
- * Identify myself via ps
+ * Flush stdio channels (see comments in BackendStartup)
*/
- switch (xlop)
- {
- case BS_XLOG_STARTUP:
- statmsg = "startup subprocess";
- break;
- case BS_XLOG_CHECKPOINT:
- statmsg = "checkpoint subprocess";
- break;
- case BS_XLOG_BGWRITER:
- statmsg = "bgwriter subprocess";
- break;
- case BS_XLOG_SHUTDOWN:
- statmsg = "shutdown subprocess";
- break;
- default:
- statmsg = "??? subprocess";
- break;
- }
- init_ps_display(statmsg, "", "");
- set_ps_display("");
-}
-
+ fflush(stdout);
+ fflush(stderr);
-static pid_t
-SSDataBase(int xlop)
-{
- pid_t pid;
- Backend *bn;
+#ifdef EXEC_BACKEND
-#ifndef EXEC_BACKEND
-#ifdef LINUX_PROFILE
- struct itimerval prof_itimer;
-#endif
-#else
- char idbuf[32];
- char ddirbuf[MAXPGPATH];
-#endif
+ pid = postmaster_forkexec(ac, av);
- fflush(stdout);
- fflush(stderr);
+#else /* !EXEC_BACKEND */
-#ifndef EXEC_BACKEND
#ifdef LINUX_PROFILE
- /* see comments in BackendRun */
+ /* see comments in BackendStartup */
getitimer(ITIMER_PROF, &prof_itimer);
#endif
beos_before_backend_startup();
#endif
- /* Non EXEC_BACKEND case; fork here */
- if ((pid = fork()) == 0) /* child */
-#endif
- {
- char *av[10];
- int ac = 0;
- char nbbuf[32];
- char xlbuf[32];
+ pid = fork();
-#ifndef EXEC_BACKEND
+ if (pid == 0) /* child */
+ {
#ifdef LINUX_PROFILE
setitimer(ITIMER_PROF, &prof_itimer, NULL);
#endif
beos_backend_startup();
#endif
+ IsUnderPostmaster = true; /* we are a postmaster subprocess now */
+
/* Close the postmaster's sockets */
ClosePostmasterPorts(true);
- SSDataBaseInit(xlop);
-#else
- if (!write_backend_variables(NULL))
- return -1; /* log issued by write_backend_variables */
-#endif
-
- /* Set up command-line arguments for subprocess */
- av[ac++] = "postgres";
-
-#ifdef EXEC_BACKEND
- av[ac++] = "-boot";
-#endif
- snprintf(nbbuf, sizeof(nbbuf), "-B%d", NBuffers);
- av[ac++] = nbbuf;
-
- snprintf(xlbuf, sizeof(xlbuf), "-x%d", xlop);
- av[ac++] = xlbuf;
-
-#ifdef EXEC_BACKEND
- /* pass data dir before end of secure switches (-p) */
- snprintf(ddirbuf, MAXPGPATH, "\"%s\"", DataDir);
- av[ac++] = "-D";
- av[ac++] = ddirbuf;
-
- /* and the backend identifier + dbname */
- snprintf(idbuf, sizeof(idbuf), "-p%lu,template1", tmpBackendFileNum);
- av[ac++] = idbuf;
-#else
- av[ac++] = "-p";
- av[ac++] = "template1";
-#endif
+ /* Lose the postmaster's on-exit routines and port connections */
+ on_exit_reset();
- av[ac] = NULL;
-
- Assert(ac < lengthof(av));
-
-#ifdef EXEC_BACKEND
- /* EXEC_BACKEND case; fork/exec here */
-#ifdef WIN32
- pid = win32_forkexec(postgres_exec_path, av); /* logs on error */
-#else
- if ((pid = fork()) == 0 && (execv(postgres_exec_path, av) == -1))
- {
- /* in child */
- elog(ERROR, "unable to execv in SSDataBase: %m");
- exit(0);
- }
-#endif
-#else
BootstrapMain(ac, av);
ExitPostmaster(0);
-#endif
}
- /* in parent */
+#endif /* EXEC_BACKEND */
+
if (pid < 0)
{
-#ifndef EXEC_BACKEND
+ /* in parent, fork failed */
+ int save_errno = errno;
+
#ifdef __BEOS__
/* Specific beos actions before backend startup */
beos_backend_startup_failed();
#endif
-#endif
+ errno = save_errno;
switch (xlop)
{
case BS_XLOG_STARTUP:
}
/*
+ * in parent, successful fork
+ *
* The startup and shutdown processes are not considered normal
* backends, but the checkpoint and bgwriter processes are. They must
* be added to the list of backends.
* functions
*/
#include "storage/spin.h"
-extern XLogwrtResult LogwrtResult;
+
extern slock_t *ShmemLock;
extern slock_t *ShmemIndexLock;
extern void *ShmemIndexAlloc;
#define write_var(var,fp) fwrite((void*)&(var),sizeof(var),1,fp)
#define read_var(var,fp) fread((void*)&(var),sizeof(var),1,fp)
-#define get_tmp_backend_file_name(buf,id) \
- do { \
- Assert(DataDir); \
- sprintf((buf), \
- "%s/%s/%s.backend_var.%lu", \
- DataDir, \
- PG_TEMP_FILES_DIR, \
- PG_TEMP_FILE_PREFIX, \
- (id)); \
- } while (0)
static bool
-write_backend_variables(Port *port)
+write_backend_variables(char *filename, Port *port)
{
- char filename[MAXPGPATH];
+ static unsigned long tmpBackendFileNum = 0;
FILE *fp;
+ char str_buf[MAXPGPATH];
- get_tmp_backend_file_name(filename, ++tmpBackendFileNum);
+ /* Calculate name for temp file in caller's buffer */
+ Assert(DataDir);
+ snprintf(filename, MAXPGPATH, "%s/%s/%s.backend_var.%lu",
+ DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
+ ++tmpBackendFileNum);
/* Open file */
fp = AllocateFile(filename, PG_BINARY_W);
/* As per OpenTemporaryFile... */
char dirname[MAXPGPATH];
- sprintf(dirname, "%s/%s", DataDir, PG_TEMP_FILES_DIR);
+ snprintf(dirname, MAXPGPATH, "%s/%s", DataDir, PG_TEMP_FILES_DIR);
mkdir(dirname, S_IRWXU);
fp = AllocateFile(filename, PG_BINARY_W);
if (!fp)
{
- ereport(ERROR,
+ ereport(LOG,
(errcode_for_file_access(),
- errmsg("could not write to file \"%s\": %m", filename)));
+ errmsg("could not create file \"%s\": %m",
+ filename)));
return false;
}
}
/* Write vars */
- if (port)
- {
- write_var(port->sock, fp);
- write_var(port->proto, fp);
- write_var(port->laddr, fp);
- write_var(port->raddr, fp);
- write_var(port->canAcceptConnections, fp);
- write_var(port->cryptSalt, fp);
- write_var(port->md5Salt, fp);
- }
- write_var(MyCancelKey, fp);
+ write_var(port->sock, fp);
+ write_var(port->proto, fp);
+ write_var(port->laddr, fp);
+ write_var(port->raddr, fp);
+ write_var(port->canAcceptConnections, fp);
+ write_var(port->cryptSalt, fp);
+ write_var(port->md5Salt, fp);
+
+ /*
+ * XXX FIXME later: writing these strings as MAXPGPATH bytes always is
+ * probably a waste of resources
+ */
- write_var(LogwrtResult, fp);
+ StrNCpy(str_buf, DataDir, MAXPGPATH);
+ fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+
+ write_var(MyCancelKey, fp);
write_var(UsedShmemSegID, fp);
write_var(UsedShmemSegAddr, fp);
write_var(ProcStructLock, fp);
write_var(pgStatSock, fp);
- write_var(PreAuthDelay, fp);
write_var(debug_flag, fp);
write_var(PostmasterPid, fp);
fwrite((void *) my_exec_path, MAXPGPATH, 1, fp);
+ fwrite((void *) ExtraOptions, sizeof(ExtraOptions), 1, fp);
+
+ StrNCpy(str_buf, setlocale(LC_COLLATE, NULL), MAXPGPATH);
+ fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+ StrNCpy(str_buf, setlocale(LC_CTYPE, NULL), MAXPGPATH);
+ fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+
/* Release file */
if (FreeFile(fp))
{
return true;
}
-void
-read_backend_variables(unsigned long id, Port *port)
+static void
+read_backend_variables(char *filename, Port *port)
{
- char filename[MAXPGPATH];
FILE *fp;
-
- get_tmp_backend_file_name(filename, id);
+ char str_buf[MAXPGPATH];
/* Open file */
fp = AllocateFile(filename, PG_BINARY_R);
if (!fp)
- {
- ereport(ERROR,
+ ereport(FATAL,
(errcode_for_file_access(),
- errmsg("could not read from backend_variables file \"%s\": %m", filename)));
- return;
- }
+ errmsg("could not read from backend variables file \"%s\": %m",
+ filename)));
/* Read vars */
- if (port)
- {
- read_var(port->sock, fp);
- read_var(port->proto, fp);
- read_var(port->laddr, fp);
- read_var(port->raddr, fp);
- read_var(port->canAcceptConnections, fp);
- read_var(port->cryptSalt, fp);
- read_var(port->md5Salt, fp);
- }
- read_var(MyCancelKey, fp);
+ read_var(port->sock, fp);
+ read_var(port->proto, fp);
+ read_var(port->laddr, fp);
+ read_var(port->raddr, fp);
+ read_var(port->canAcceptConnections, fp);
+ read_var(port->cryptSalt, fp);
+ read_var(port->md5Salt, fp);
- read_var(LogwrtResult, fp);
+ fread((void *) str_buf, MAXPGPATH, 1, fp);
+ SetDataDir(str_buf);
+
+ read_var(MyCancelKey, fp);
read_var(UsedShmemSegID, fp);
read_var(UsedShmemSegAddr, fp);
read_var(ProcStructLock, fp);
read_var(pgStatSock, fp);
- read_var(PreAuthDelay, fp);
read_var(debug_flag, fp);
read_var(PostmasterPid, fp);
fread((void *) my_exec_path, MAXPGPATH, 1, fp);
+ fread((void *) ExtraOptions, sizeof(ExtraOptions), 1, fp);
+
+ fread((void *) str_buf, MAXPGPATH, 1, fp);
+ setlocale(LC_COLLATE, str_buf);
+ fread((void *) str_buf, MAXPGPATH, 1, fp);
+ setlocale(LC_CTYPE, str_buf);
+
/* Release file */
FreeFile(fp);
if (unlink(filename) != 0)
(errmsg_internal("unable to find backend entry with pid %d",
pid)));
}
-#endif
+
+#endif /* EXEC_BACKEND */
+
#ifdef WIN32
-pid_t
+static pid_t
win32_forkexec(const char *path, char *argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
char *p;
int i;
- char cmdLine[MAXPGPATH];
+ int j;
+ char cmdLine[MAXPGPATH * 2];
HANDLE childHandleCopy;
HANDLE waiterThread;
/* Format the cmd line */
- snprintf(cmdLine, sizeof(cmdLine), "\"%s\"", path);
+ cmdline[sizeof(cmdLine)-1] = '\0';
+ cmdline[sizeof(cmdLine)-2] = '\0';
+ snprintf(cmdLine, sizeof(cmdLine)-1, "\"%s\"", path);
i = 0;
while (argv[++i] != NULL)
{
- /* FIXME: [fork/exec] some strlen checks might be prudent here */
- strcat(cmdLine, " ");
- strcat(cmdLine, argv[i]);
+ j = strlen(cmdLine);
+ snprintf(cmdLine+j, sizeof(cmdLine)-1-j, " \"%s\"", argv[i]);
+ }
+ if (cmdline[sizeof(cmdLine)-2] != '\0')
+ {
+ elog(LOG, "subprocess command line too long");
+ return -1;
}
-
- /*
- * The following snippet can disappear when we consistently use
- * forward slashes.
- */
- p = cmdLine;
- while (*(p++) != '\0')
- if (*p == '/')
- *p = '\\';
memset(&pi, 0, sizeof(pi));
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
- elog(ERROR, "CreateProcess call failed (%i): %m", (int) GetLastError());
+ elog(LOG, "CreateProcess call failed (%d): %m", (int) GetLastError());
return -1;
}
if (!IsUnderPostmaster)
+ {
/* We are the Postmaster creating a child... */
win32_AddChild(pi.dwProcessId, pi.hProcess);
+ }
if (!DuplicateHandle(GetCurrentProcess(),
pi.hProcess,
FALSE,
DUPLICATE_SAME_ACCESS))
ereport(FATAL,
- (errmsg_internal("failed to duplicate child handle: %i", (int) GetLastError())));
- waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter, (LPVOID) childHandleCopy, 0, NULL);
+ (errmsg_internal("failed to duplicate child handle: %d",
+ (int) GetLastError())));
+
+ waiterThread = CreateThread(NULL, 64 * 1024, win32_sigchld_waiter,
+ (LPVOID) childHandleCopy, 0, NULL);
if (!waiterThread)
ereport(FATAL,
- (errmsg_internal("failed to create sigchld waiter thread: %i", (int) GetLastError())));
+ (errmsg_internal("failed to create sigchld waiter thread: %d",
+ (int) GetLastError())));
CloseHandle(waiterThread);
if (IsUnderPostmaster)
else
ereport(FATAL,
(errmsg_internal("unable to add child entry with pid %lu",
- pid)));
+ (unsigned long) pid)));
}
static void
ereport(WARNING,
(errmsg_internal("unable to find child entry with pid %lu",
- pid)));
+ (unsigned long) pid)));
}
static pid_t
if (r == WAIT_OBJECT_0)
pg_queue_signal(SIGCHLD);
else
- fprintf(stderr, "ERROR: Failed to wait on child process handle: %i\n", (int) GetLastError());
+ fprintf(stderr, "ERROR: Failed to wait on child process handle: %i\n",
+ (int) GetLastError());
CloseHandle(procHandle);
return 0;
}
-#endif
+#endif /* WIN32 */