aboutsummaryrefslogtreecommitdiff
path: root/src/backend/postmaster/postmaster.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/postmaster/postmaster.c')
-rw-r--r--src/backend/postmaster/postmaster.c939
1 files changed, 480 insertions, 459 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 7ef3ea4bd71..9726a92fd0e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -10,38 +10,38 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.24 1996/11/12 06:46:36 bryanh Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.25 1996/11/14 10:24:01 bryanh Exp $
*
* NOTES
*
* Initialization:
- * The Postmaster sets up a few shared memory data structures
- * for the backends. It should at the very least initialize the
- * lock manager.
+ * The Postmaster sets up a few shared memory data structures
+ * for the backends. It should at the very least initialize the
+ * lock manager.
*
* Synchronization:
- * The Postmaster shares memory with the backends and will have to lock
- * the shared memory it accesses. The Postmaster should never block
- * on messages from clients.
- *
+ * The Postmaster shares memory with the backends and will have to lock
+ * the shared memory it accesses. The Postmaster should never block
+ * on messages from clients.
+ *
* Garbage Collection:
- * The Postmaster cleans up after backends if they have an emergency
- * exit and/or core dump.
+ * The Postmaster cleans up after backends if they have an emergency
+ * exit and/or core dump.
*
* Communication:
*
*-------------------------------------------------------------------------
*/
- /* moved here to prevent double define */
-#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+ /* moved here to prevent double define */
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
#ifndef MAXHOSTNAMELEN
-#include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
#endif
#include "postgres.h"
-#include <signal.h> /* for other stuff */
-#include "libpq/pqsignal.h" /* substitute for <signal.h> */
+#include <signal.h> /* for other stuff */
+#include "libpq/pqsignal.h" /* substitute for <signal.h> */
#include <string.h>
#include <stdlib.h>
@@ -50,13 +50,13 @@
#endif /* !NO_UNISTD_H */
#include <ctype.h>
-#include <sys/types.h> /* for fd_set stuff */
-#include <sys/stat.h> /* for umask */
+#include <sys/types.h> /* for fd_set stuff */
+#include <sys/stat.h> /* for umask */
#include <sys/time.h>
#include <sys/socket.h>
#if defined(USE_LIMITS_H)
# include <machine/limits.h>
-# define MAXINT INT_MAX
+# define MAXINT INT_MAX
#else
# include <values.h>
#endif /* !USE_LIMITS_H */
@@ -103,7 +103,7 @@
* but I left this structure around in case that changed.
*/
typedef struct bkend {
- int pid; /* process id of backend */
+ int pid; /* process id of backend */
} Backend;
/* list of active backends. For garbage collection only now. */
@@ -113,24 +113,27 @@ static Dllist* BackendList;
/* list of ports associated with still open, but incomplete connections */
static Dllist* PortList;
-static short PostPortName = -1;
-static short ActiveBackends = FALSE;
-static int NextBackendId = MAXINT; /* XXX why? */
-static char *progname = (char *) NULL;
+static short PostPortName = -1;
+static short ActiveBackends = FALSE;
+static int NextBackendId = MAXINT; /* XXX why? */
+static char *progname = (char *) NULL;
-char *DataDir = (char *) NULL;
+char *DataDir;
+ /* The PGDATA directory user says to use, or defaults to via environment
+ variable. NULL if no option given and no environment variable set
+ */
/*
* Default Values
*/
-static char Execfile[MAXPATHLEN] = "";
+static char Execfile[MAXPATHLEN] = "";
-static int ServerSock = INVALID_SOCK; /* stream socket server */
+static int ServerSock = INVALID_SOCK; /* stream socket server */
/*
* Set by the -o option
*/
-static char ExtraOptions[ARGV_SIZE] = "";
+static char ExtraOptions[ARGV_SIZE] = "";
/*
* These globals control the behavior of the postmaster in case some
@@ -139,8 +142,8 @@ static char ExtraOptions[ARGV_SIZE] = "";
* the postmaster stop (rather than kill) peers and not reinitialize
* shared data structures.
*/
-static int Reinit = 1;
-static int SendStop = 0;
+static int Reinit = 1;
+static int SendStop = 0;
static int MultiplexedBackends = 0;
static int MultiplexedBackendPort;
@@ -160,7 +163,6 @@ static void CleanupProc(int pid, int exitstatus);
static int DoExec(StartupInfo *packet, int portFd);
static void ExitPostmaster(int status);
static void usage(const char *);
-static void checkDataDir(void);
int ServerLoop(void);
int BackendStartup(StartupInfo *packet, Port *port, int *pidPtr);
static void send_error_reply(Port *port, const char *errormsg);
@@ -168,142 +170,194 @@ static void send_error_reply(Port *port, const char *errormsg);
extern char *optarg;
extern int optind, opterr;
+
+
+static void
+checkDataDir(const char *DataDir, bool *DataDirOK)
+{
+ if (DataDir == NULL) {
+ fprintf(stderr, "%s does not know where to find the database system "
+ "data. You must specify the directory that contains the "
+ "database system either by specifying the -D invocation "
+ "option or by setting the PGDATA environment variable.\n\n",
+ progname);
+ *DataDirOK = false;
+ } else {
+ char path[MAXPATHLEN];
+ FILE *fp;
+
+ sprintf(path, "%s%cbase%ctemplate1%cpg_class",
+ DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR);
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "%s does not find the database system. "
+ "Expected to find it "
+ "in the PGDATA directory \"%s\", but unable to open file "
+ "with pathname \"%s\".\n\n",
+ progname, DataDir, path);
+ *DataDirOK = false;
+ } else {
+ char *reason;
+ /* reason ValidatePgVersion failed. NULL if didn't */
+
+ fclose(fp);
+
+#ifndef WIN32
+ ValidatePgVersion(DataDir, &reason);
+#else
+ reason = NULL;
+#endif /* WIN32 */
+ if (reason) {
+ fprintf(stderr,
+ "Database system in directory %s "
+ "is not compatible with this version of "
+ "Postgres, or we are unable to read the "
+ "PG_VERSION file. "
+ "Explanation from ValidatePgVersion: %s\n\n",
+ DataDir, reason);
+ free(reason);
+ *DataDirOK = false;
+ } else *DataDirOK = true;
+ }
+ }
+}
+
+
+
int
PostmasterMain(int argc, char *argv[])
{
- extern int NBuffers; /* from buffer/bufmgr.c */
- extern bool IsPostmaster; /* from smgr/mm.c */
- int opt;
- char *hostName;
- int status;
- int silentflag = 0;
- char hostbuf[MAXHOSTNAMELEN];
+ extern int NBuffers; /* from buffer/bufmgr.c */
+ extern bool IsPostmaster; /* from smgr/mm.c */
+ int opt;
+ char *hostName;
+ int status;
+ int silentflag = 0;
+ char hostbuf[MAXHOSTNAMELEN];
+ bool DataDirOK; /* We have a usable PGDATA value */
#if defined(WIN32)
WSADATA WSAData;
#endif /* WIN32 */
progname = argv[0];
+ IsPostmaster = true;
+
/* for security, no dir or file created can be group or other accessible */
(void) umask((mode_t) 0077);
if (!(hostName = getenv("PGHOST"))) {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- (void) strcpy(hostbuf, "localhost");
- hostName = hostbuf;
+ if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
+ (void) strcpy(hostbuf, "localhost");
+ hostName = hostbuf;
}
+
+ DataDir = getenv("PGDATA"); /* default value */
opterr = 0;
while ((opt = getopt(argc, argv, "a:B:b:D:dmM:no:p:Ss")) != EOF) {
- switch (opt) {
- case 'a':
- /* Set the authentication system. */
- be_setauthsvc(optarg);
- break;
- case 'B':
- /*
- * The number of buffers to create. Setting this
- * option means we have to start each backend with
- * a -B # to make sure they know how many buffers
- * were allocated.
- */
- NBuffers = atol(optarg);
- (void) strcat(ExtraOptions, " -B ");
- (void) strcat(ExtraOptions, optarg);
- break;
- case 'b':
- /* Set the backend executable file to use. */
- if (!ValidateBackend(optarg))
- strcpy(Execfile, optarg);
- else {
- fprintf(stderr, "%s: invalid backend \"%s\"\n",
- progname, optarg);
- exit(2);
- }
- break;
- case 'D':
- /* Set PGDATA from the command line. */
- DataDir = optarg;
- break;
- case 'd':
- /*
- * Turn on debugging for the postmaster and the backend
- * servers descended from it.
- */
- if ((optind < argc) && *argv[optind] != '-') {
- DebugLvl = atoi(argv[optind]);
- optind++;
- }
- else
- DebugLvl = 1;
- break;
- case 'm':
- MultiplexedBackends = 1;
- MultiplexedBackendPort = atoi(optarg);
- break;
- case 'M':
- /* ignore this flag. This may be passed in because the
- program was run as 'postgres -M' instead of 'postmaster' */
- break;
- case 'n':
- /* Don't reinit shared mem after abnormal exit */
- Reinit = 0;
- break;
- case 'o':
- /*
- * Other options to pass to the backend on the
- * command line -- useful only for debugging.
- */
- (void) strcat(ExtraOptions, " ");
- (void) strcat(ExtraOptions, optarg);
- break;
- case 'p':
- /* Set PGPORT by hand. */
- PostPortName = (short) atoi(optarg);
- break;
- case 'S':
- /*
- * Start in 'S'ilent mode (disassociate from controlling tty).
- * You may also think of this as 'S'ysV mode since it's most
- * badly needed on SysV-derived systems like SVR4 and HP-UX.
- */
- silentflag = 1;
- break;
- case 's':
- /*
- * In the event that some backend dumps core,
- * send SIGSTOP, rather than SIGUSR1, to all
- * its peers. This lets the wily post_hacker
- * collect core dumps from everyone.
- */
- SendStop = 1;
- break;
- default:
- /* usage() never returns */
- usage(progname);
- break;
- }
+ switch (opt) {
+ case 'a':
+ /* Set the authentication system. */
+ be_setauthsvc(optarg);
+ break;
+ case 'B':
+ /*
+ * The number of buffers to create. Setting this
+ * option means we have to start each backend with
+ * a -B # to make sure they know how many buffers
+ * were allocated.
+ */
+ NBuffers = atol(optarg);
+ (void) strcat(ExtraOptions, " -B ");
+ (void) strcat(ExtraOptions, optarg);
+ break;
+ case 'b':
+ /* Set the backend executable file to use. */
+ if (!ValidateBackend(optarg))
+ strcpy(Execfile, optarg);
+ else {
+ fprintf(stderr, "%s: invalid backend \"%s\"\n",
+ progname, optarg);
+ exit(2);
+ }
+ break;
+ case 'D':
+ /* Set PGDATA from the command line. */
+ DataDir = optarg;
+ break;
+ case 'd':
+ /*
+ * Turn on debugging for the postmaster and the backend
+ * servers descended from it.
+ */
+ if ((optind < argc) && *argv[optind] != '-') {
+ DebugLvl = atoi(argv[optind]);
+ optind++;
+ }
+ else
+ DebugLvl = 1;
+ break;
+ case 'm':
+ MultiplexedBackends = 1;
+ MultiplexedBackendPort = atoi(optarg);
+ break;
+ case 'M':
+ /* ignore this flag. This may be passed in because the
+ program was run as 'postgres -M' instead of 'postmaster' */
+ break;
+ case 'n':
+ /* Don't reinit shared mem after abnormal exit */
+ Reinit = 0;
+ break;
+ case 'o':
+ /*
+ * Other options to pass to the backend on the
+ * command line -- useful only for debugging.
+ */
+ (void) strcat(ExtraOptions, " ");
+ (void) strcat(ExtraOptions, optarg);
+ break;
+ case 'p':
+ /* Set PGPORT by hand. */
+ PostPortName = (short) atoi(optarg);
+ break;
+ case 'S':
+ /*
+ * Start in 'S'ilent mode (disassociate from controlling tty).
+ * You may also think of this as 'S'ysV mode since it's most
+ * badly needed on SysV-derived systems like SVR4 and HP-UX.
+ */
+ silentflag = 1;
+ break;
+ case 's':
+ /*
+ * In the event that some backend dumps core,
+ * send SIGSTOP, rather than SIGUSR1, to all
+ * its peers. This lets the wily post_hacker
+ * collect core dumps from everyone.
+ */
+ SendStop = 1;
+ break;
+ default:
+ /* usage() never returns */
+ usage(progname);
+ break;
+ }
}
if (PostPortName == -1)
- PostPortName = pq_getport();
+ PostPortName = pq_getport();
- IsPostmaster = true;
-
- if (!DataDir)
- DataDir = GetPGData();
+ checkDataDir(DataDir, &DataDirOK); /* issues error messages */
+ if (!DataDirOK) {
+ fprintf(stderr, "No data directory -- can't proceed.\n");
+ exit(2);
+ }
- /*
- * check whether the data directory exists. Passing this test doesn't
- * gaurantee we are accessing the right data base but is a first barrier
- * to site administrators who starts up the postmaster without realizing
- * it cannot access the data base.
- */
- checkDataDir();
-
if (!Execfile[0] && FindBackend(Execfile, argv[0]) < 0) {
- fprintf(stderr, "%s: could not find backend to execute...\n",
- argv[0]);
- exit(1);
+ fprintf(stderr, "%s: could not find backend to execute...\n",
+ argv[0]);
+ exit(1);
}
@@ -321,9 +375,9 @@ PostmasterMain(int argc, char *argv[])
status = StreamServerPort(hostName, PostPortName, &ServerSock);
if (status != STATUS_OK) {
- fprintf(stderr, "%s: cannot create stream port\n",
- progname);
- exit(1);
+ fprintf(stderr, "%s: cannot create stream port\n",
+ progname);
+ exit(1);
}
/* set up shared memory and semaphores */
@@ -338,7 +392,7 @@ PostmasterMain(int argc, char *argv[])
PortList = DLNewList();
if (silentflag)
- pmdaemonize();
+ pmdaemonize();
signal(SIGINT, pmdie);
#ifndef WIN32
@@ -363,12 +417,12 @@ pmdaemonize(void)
int i;
if (fork())
- exit(0);
+ exit(0);
if (setsid() < 0) {
- fprintf(stderr, "%s: ", progname);
- perror("cannot disassociate from controlling TTY");
- exit(1);
+ fprintf(stderr, "%s: ", progname);
+ perror("cannot disassociate from controlling TTY");
+ exit(1);
}
i = open(NULL_DEV, O_RDWR);
(void) dup2(i, 0);
@@ -398,9 +452,9 @@ usage(const char *progname)
int
ServerLoop(void)
{
- int serverFd = ServerSock;
- fd_set rmask, basemask;
- int nSockets, nSelected, status, newFd;
+ int serverFd = ServerSock;
+ fd_set rmask, basemask;
+ int nSockets, nSelected, status, newFd;
Dlelem *next, *curr;
/* int orgsigmask = sigblock(0); */
sigset_t oldsigmask, newsigmask;
@@ -413,104 +467,104 @@ ServerLoop(void)
sigemptyset(&newsigmask);
sigaddset(&newsigmask,SIGCHLD);
for (;;) {
-/* sigsetmask(orgsigmask); */
- sigprocmask(SIG_SETMASK,&oldsigmask,0);
- newFd = -1;
- memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
- if ((nSelected = select(nSockets, &rmask,
- (fd_set *) NULL,
- (fd_set *) NULL,
- (struct timeval *) NULL)) < 0) {
- if (errno == EINTR)
- continue;
- fprintf(stderr, "%s: ServerLoop: select failed\n",
- progname);
- return(STATUS_ERROR);
+/* sigsetmask(orgsigmask); */
+ sigprocmask(SIG_SETMASK,&oldsigmask,0);
+ newFd = -1;
+ memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
+ if ((nSelected = select(nSockets, &rmask,
+ (fd_set *) NULL,
+ (fd_set *) NULL,
+ (struct timeval *) NULL)) < 0) {
+ if (errno == EINTR)
+ continue;
+ fprintf(stderr, "%s: ServerLoop: select failed\n",
+ progname);
+ return(STATUS_ERROR);
}
- /* [TRH]
- * To avoid race conditions, block SIGCHLD signals while we are
- * handling the request. (both reaper() and ConnCreate()
- * manipulate the BackEnd list, and reaper() calls free() which is
- * usually non-reentrant.)
- */
- sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
-/* sigblock(sigmask(SIGCHLD)); */ /* XXX[TRH] portability */
- if (DebugLvl > 1) {
- fprintf(stderr, "%s: ServerLoop: %d sockets pending\n",
- progname, nSelected);
- }
-
- /* new connection pending on our well-known port's socket */
- if (FD_ISSET(ServerSock, &rmask)) {
- /*
- * connect and make an addition to PortList. If
- * the connection dies and we notice it, just forget
- * about the whole thing.
- */
- if (ConnCreate(serverFd, &newFd) == STATUS_OK) {
- if (newFd >= nSockets)
- nSockets = newFd + 1;
- FD_SET(newFd, &rmask);
- FD_SET(newFd, &basemask);
- if (DebugLvl)
- fprintf(stderr, "%s: ServerLoop: connect on %d\n",
- progname, newFd);
- }
- --nSelected;
- FD_CLR(ServerSock, &rmask);
- }
+ /* [TRH]
+ * To avoid race conditions, block SIGCHLD signals while we are
+ * handling the request. (both reaper() and ConnCreate()
+ * manipulate the BackEnd list, and reaper() calls free() which is
+ * usually non-reentrant.)
+ */
+ sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
+/* sigblock(sigmask(SIGCHLD)); */ /* XXX[TRH] portability */
+ if (DebugLvl > 1) {
+ fprintf(stderr, "%s: ServerLoop: %d sockets pending\n",
+ progname, nSelected);
+ }
+
+ /* new connection pending on our well-known port's socket */
+ if (FD_ISSET(ServerSock, &rmask)) {
+ /*
+ * connect and make an addition to PortList. If
+ * the connection dies and we notice it, just forget
+ * about the whole thing.
+ */
+ if (ConnCreate(serverFd, &newFd) == STATUS_OK) {
+ if (newFd >= nSockets)
+ nSockets = newFd + 1;
+ FD_SET(newFd, &rmask);
+ FD_SET(newFd, &basemask);
+ if (DebugLvl)
+ fprintf(stderr, "%s: ServerLoop: connect on %d\n",
+ progname, newFd);
+ }
+ --nSelected;
+ FD_CLR(ServerSock, &rmask);
+ }
- if (DebugLvl > 1) {
- fprintf(stderr, "%s: ServerLoop:\tnSelected=%d\n",
- progname, nSelected);
- curr = DLGetHead(PortList);
- while (curr) {
- Port *port = DLE_VAL(curr);
-
- fprintf(stderr, "%s: ServerLoop:\t\tport %d%s pending\n",
- progname, port->sock,
- FD_ISSET(port->sock, &rmask)
- ? "" :
- " not");
- curr = DLGetSucc(curr);
- }
- }
-
- curr = DLGetHead(PortList);
-
- while (curr) {
- Port *port = (Port*)DLE_VAL(curr);
- int lastbytes = port->nBytes;
-
- if (FD_ISSET(port->sock, &rmask) && port->sock != newFd) {
- if (DebugLvl > 1)
- fprintf(stderr, "%s: ServerLoop:\t\thandling %d\n",
- progname, port->sock);
- --nSelected;
-
- /*
- * Read the incoming packet into its packet buffer.
- * Read the connection id out of the packet so we
- * know who the packet is from.
- */
- status = PacketReceive(port, &port->buf, NON_BLOCKING);
- switch (status) {
- case STATUS_OK: {
+ if (DebugLvl > 1) {
+ fprintf(stderr, "%s: ServerLoop:\tnSelected=%d\n",
+ progname, nSelected);
+ curr = DLGetHead(PortList);
+ while (curr) {
+ Port *port = DLE_VAL(curr);
+
+ fprintf(stderr, "%s: ServerLoop:\t\tport %d%s pending\n",
+ progname, port->sock,
+ FD_ISSET(port->sock, &rmask)
+ ? "" :
+ " not");
+ curr = DLGetSucc(curr);
+ }
+ }
+
+ curr = DLGetHead(PortList);
+
+ while (curr) {
+ Port *port = (Port*)DLE_VAL(curr);
+ int lastbytes = port->nBytes;
+
+ if (FD_ISSET(port->sock, &rmask) && port->sock != newFd) {
+ if (DebugLvl > 1)
+ fprintf(stderr, "%s: ServerLoop:\t\thandling %d\n",
+ progname, port->sock);
+ --nSelected;
+
+ /*
+ * Read the incoming packet into its packet buffer.
+ * Read the connection id out of the packet so we
+ * know who the packet is from.
+ */
+ status = PacketReceive(port, &port->buf, NON_BLOCKING);
+ switch (status) {
+ case STATUS_OK: {
int CSstatus; /* Completion status of ConnStartup */
char errormsg[200]; /* error msg from ConnStartup */
- ConnStartup(port, &CSstatus, errormsg, sizeof(errormsg));
+ ConnStartup(port, &CSstatus, errormsg, sizeof(errormsg));
if (CSstatus == STATUS_ERROR)
send_error_reply(port, errormsg);
- ActiveBackends = TRUE;
+ ActiveBackends = TRUE;
}
- /*FALLTHROUGH*/
- case STATUS_INVALID:
- if (DebugLvl)
- fprintf(stderr, "%s: ServerLoop:\t\tdone with %d\n",
- progname, port->sock);
- break;
+ /*FALLTHROUGH*/
+ case STATUS_INVALID:
+ if (DebugLvl)
+ fprintf(stderr, "%s: ServerLoop:\t\tdone with %d\n",
+ progname, port->sock);
+ break;
case STATUS_BAD_PACKET:
/*
* This is a bogus client, kill the connection
@@ -519,41 +573,41 @@ ServerLoop(void)
if (DebugLvl)
fprintf(stderr, "%s: ServerLoop:\t\tbad packet format (reported packet size of %d read on port %d\n", progname, port->nBytes, port->sock);
break;
- case STATUS_NOT_DONE:
- if (DebugLvl)
- fprintf(stderr, "%s: ServerLoop:\t\tpartial packet (%d bytes actually read) on %d\n",
- progname, port->nBytes, port->sock);
- /*
- * If we've received at least a PacketHdr's worth of data
- * and we're still receiving data each time we read, we're
- * ok. If the client gives us less than a PacketHdr at
- * the beginning, just kill the connection and forget
- * about the whole thing.
- */
- if (lastbytes < port->nBytes) {
- if (DebugLvl)
- fprintf(stderr, "%s: ServerLoop:\t\tpartial packet on %d ok\n",
- progname, port->sock);
- curr = DLGetSucc(curr);
- continue;
- }
- break;
- case STATUS_ERROR: /* system call error - die */
- fprintf(stderr, "%s: ServerLoop:\t\terror receiving packet\n",
- progname);
- return(STATUS_ERROR);
- }
- FD_CLR(port->sock, &basemask);
- StreamClose(port->sock);
- next = DLGetSucc(curr);
- DLRemove(curr);
- DLFreeElem(curr);
- curr = next;
+ case STATUS_NOT_DONE:
+ if (DebugLvl)
+ fprintf(stderr, "%s: ServerLoop:\t\tpartial packet (%d bytes actually read) on %d\n",
+ progname, port->nBytes, port->sock);
+ /*
+ * If we've received at least a PacketHdr's worth of data
+ * and we're still receiving data each time we read, we're
+ * ok. If the client gives us less than a PacketHdr at
+ * the beginning, just kill the connection and forget
+ * about the whole thing.
+ */
+ if (lastbytes < port->nBytes) {
+ if (DebugLvl)
+ fprintf(stderr, "%s: ServerLoop:\t\tpartial packet on %d ok\n",
+ progname, port->sock);
+ curr = DLGetSucc(curr);
+ continue;
+ }
+ break;
+ case STATUS_ERROR: /* system call error - die */
+ fprintf(stderr, "%s: ServerLoop:\t\terror receiving packet\n",
+ progname);
+ return(STATUS_ERROR);
+ }
+ FD_CLR(port->sock, &basemask);
+ StreamClose(port->sock);
+ next = DLGetSucc(curr);
+ DLRemove(curr);
+ DLFreeElem(curr);
+ curr = next;
continue;
- }
- curr = DLGetSucc(curr);
- }
- Assert(nSelected == 0);
+ }
+ curr = DLGetSucc(curr);
+ }
+ Assert(nSelected == 0);
}
}
@@ -574,7 +628,7 @@ ConnStartup(Port *port, int *status,
{
MsgType msgType;
char namebuf[NAMEDATALEN + 1];
- int pid;
+ int pid;
PacketBuf *p;
StartupInfo sp;
char *tmp;
@@ -708,23 +762,23 @@ send_error_reply(Port *port, const char *errormsg)
static int
ConnCreate(int serverFd, int *newFdP)
{
- int status;
- Port *port;
+ int status;
+ Port *port;
if (!(port = (Port *) calloc(1, sizeof(Port)))) {
- fprintf(stderr, "%s: ConnCreate: malloc failed\n",
- progname);
- ExitPostmaster(1);
+ fprintf(stderr, "%s: ConnCreate: malloc failed\n",
+ progname);
+ ExitPostmaster(1);
}
if ((status = StreamConnection(serverFd, port)) != STATUS_OK) {
- StreamClose(port->sock);
- free(port);
+ StreamClose(port->sock);
+ free(port);
}
else {
- DLAddHead(PortList, DLNewElem(port));
- *newFdP = port->sock;
+ DLAddHead(PortList, DLNewElem(port));
+ *newFdP = port->sock;
}
return (status);
@@ -736,7 +790,7 @@ ConnCreate(int serverFd, int *newFdP)
static void
reset_shared(short port)
{
- IPCKey key;
+ IPCKey key;
key = SystemPortAddressCreateIPCKey((SystemPortAddress) port);
CreateSharedMemoryAndSemaphores(key);
@@ -758,15 +812,15 @@ pmdie(SIGNAL_ARGS)
static void
reaper(SIGNAL_ARGS)
{
- int status; /* backend exit status */
- int pid; /* process id of dead backend */
+ int status; /* backend exit status */
+ int pid; /* process id of dead backend */
if (DebugLvl)
- fprintf(stderr, "%s: reaping dead processes...\n",
- progname);
+ fprintf(stderr, "%s: reaping dead processes...\n",
+ progname);
#ifndef WIN32
while((pid = waitpid(-1, &status, WNOHANG)) > 0)
- CleanupProc(pid, status);
+ CleanupProc(pid, status);
#endif /* WIN32 */
}
@@ -779,15 +833,15 @@ reaper(SIGNAL_ARGS)
*/
static void
CleanupProc(int pid,
- int exitstatus) /* child's exit status. */
+ int exitstatus) /* child's exit status. */
{
Dlelem *prev, *curr;
- Backend *bp;
- int sig;
+ Backend *bp;
+ int sig;
if (DebugLvl) {
- fprintf(stderr, "%s: CleanupProc: pid %d exited with status %d\n",
- progname, pid, exitstatus);
+ fprintf(stderr, "%s: CleanupProc: pid %d exited with status %d\n",
+ progname, pid, exitstatus);
}
/*
* -------------------------
@@ -798,57 +852,57 @@ CleanupProc(int pid,
* -------------------------
*/
if (!exitstatus) {
- curr = DLGetHead(BackendList);
- while (curr) {
- bp = (Backend*)DLE_VAL(curr);
- if (bp->pid == pid) {
- DLRemove(curr);
- DLFreeElem(curr);
- break;
- }
- curr = DLGetSucc(curr);
- }
-
- ProcRemove(pid);
-
- return;
+ curr = DLGetHead(BackendList);
+ while (curr) {
+ bp = (Backend*)DLE_VAL(curr);
+ if (bp->pid == pid) {
+ DLRemove(curr);
+ DLFreeElem(curr);
+ break;
+ }
+ curr = DLGetSucc(curr);
+ }
+
+ ProcRemove(pid);
+
+ return;
}
curr = DLGetHead(BackendList);
while (curr) {
- bp = (Backend*)DLE_VAL(curr);
-
- /*
- * -----------------
- * SIGUSR1 is the special signal that sez exit without exitpg
- * and let the user know what's going on. ProcSemaphoreKill()
- * cleans up the backends semaphore. If SendStop is set (-s on
- * the command line), then we send a SIGSTOP so that we can
- * collect core dumps from all backends by hand.
- * -----------------
- */
+ bp = (Backend*)DLE_VAL(curr);
+
+ /*
+ * -----------------
+ * SIGUSR1 is the special signal that sez exit without exitpg
+ * and let the user know what's going on. ProcSemaphoreKill()
+ * cleans up the backends semaphore. If SendStop is set (-s on
+ * the command line), then we send a SIGSTOP so that we can
+ * collect core dumps from all backends by hand.
+ * -----------------
+ */
#ifndef WIN32
- sig = (SendStop) ? SIGSTOP : SIGUSR1;
- if (bp->pid != pid) {
- if (DebugLvl)
- fprintf(stderr, "%s: CleanupProc: sending %s to process %d\n",
- progname,
- (sig == SIGUSR1)
- ? "SIGUSR1" : "SIGSTOP",
- bp->pid);
- (void) kill(bp->pid, sig);
- }
+ sig = (SendStop) ? SIGSTOP : SIGUSR1;
+ if (bp->pid != pid) {
+ if (DebugLvl)
+ fprintf(stderr, "%s: CleanupProc: sending %s to process %d\n",
+ progname,
+ (sig == SIGUSR1)
+ ? "SIGUSR1" : "SIGSTOP",
+ bp->pid);
+ (void) kill(bp->pid, sig);
+ }
#endif /* WIN32 */
- ProcRemove(bp->pid);
-
- prev = DLGetPred(curr);
- DLRemove(curr);
- DLFreeElem(curr);
- if (!prev) { /* removed head */
- curr = DLGetHead(BackendList);
- continue;
- }
- curr = DLGetSucc(curr);
+ ProcRemove(bp->pid);
+
+ prev = DLGetPred(curr);
+ DLRemove(curr);
+ DLFreeElem(curr);
+ if (!prev) { /* removed head */
+ curr = DLGetHead(BackendList);
+ continue;
+ }
+ curr = DLGetSucc(curr);
}
/*
* -------------
@@ -865,11 +919,11 @@ CleanupProc(int pid,
* ----------------
*/
if (ActiveBackends == TRUE && Reinit) {
- if (DebugLvl)
- fprintf(stderr, "%s: CleanupProc: reinitializing shared memory and semaphores\n",
- progname);
- quasi_exitpg();
- reset_shared(PostPortName);
+ if (DebugLvl)
+ fprintf(stderr, "%s: CleanupProc: reinitializing shared memory and semaphores\n",
+ progname);
+ quasi_exitpg();
+ reset_shared(PostPortName);
}
}
@@ -877,20 +931,20 @@ CleanupProc(int pid,
* BackendStartup -- start backend process
*
* returns: STATUS_ERROR if the fork/exec failed, STATUS_OK
- * otherwise.
+ * otherwise.
*
*/
int
BackendStartup(StartupInfo *packet, /* client's startup packet */
- Port *port,
- int *pidPtr)
+ Port *port,
+ int *pidPtr)
{
Backend* bn; /* for backend cleanup */
- int pid, i;
- static char envEntry[4][2 * ARGV_SIZE];
+ int pid, i;
+ static char envEntry[4][2 * ARGV_SIZE];
for (i = 0; i < 4; ++i) {
- memset(envEntry[i], 0, 2*ARGV_SIZE);
+ memset(envEntry[i], 0, 2*ARGV_SIZE);
}
/*
* Set up the necessary environment variables for the backend
@@ -903,50 +957,50 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
sprintf(envEntry[2], "PG_USER=%s", packet->user);
putenv(envEntry[2]);
if (!getenv("PGDATA")) {
- sprintf(envEntry[3], "PGDATA=%s", DataDir);
- putenv(envEntry[3]);
+ sprintf(envEntry[3], "PGDATA=%s", DataDir);
+ putenv(envEntry[3]);
}
if (DebugLvl > 2) {
- char **p;
- extern char **environ;
-
- fprintf(stderr, "%s: BackendStartup: environ dump:\n",
- progname);
- fprintf(stderr, "-----------------------------------------\n");
- for (p = environ; *p; ++p)
- fprintf(stderr, "\t%s\n", *p);
- fprintf(stderr, "-----------------------------------------\n");
+ char **p;
+ extern char **environ;
+
+ fprintf(stderr, "%s: BackendStartup: environ dump:\n",
+ progname);
+ fprintf(stderr, "-----------------------------------------\n");
+ for (p = environ; *p; ++p)
+ fprintf(stderr, "\t%s\n", *p);
+ fprintf(stderr, "-----------------------------------------\n");
}
#ifndef WIN32
- if ((pid = FORK()) == 0) { /* child */
- if (DoExec(packet, port->sock))
- fprintf(stderr, "%s child[%d]: BackendStartup: execv failed\n",
- progname, pid);
- /* use _exit to keep from double-flushing stdio */
- _exit(1);
+ if ((pid = FORK()) == 0) { /* child */
+ if (DoExec(packet, port->sock))
+ fprintf(stderr, "%s child[%d]: BackendStartup: execv failed\n",
+ progname, pid);
+ /* use _exit to keep from double-flushing stdio */
+ _exit(1);
}
/* in parent */
if (pid < 0) {
- fprintf(stderr, "%s: BackendStartup: fork failed\n",
- progname);
- return(STATUS_ERROR);
+ fprintf(stderr, "%s: BackendStartup: fork failed\n",
+ progname);
+ return(STATUS_ERROR);
}
#else
pid = DoExec(packet, port->sock);
if (pid == FALSE) {
- fprintf(stderr, "%s: BackendStartup: CreateProcess failed\n",
- progname);
- return(STATUS_ERROR);
+ fprintf(stderr, "%s: BackendStartup: CreateProcess failed\n",
+ progname);
+ return(STATUS_ERROR);
}
#endif /* WIN32 */
if (DebugLvl)
- fprintf(stderr, "%s: BackendStartup: pid %d user %s db %s socket %d\n",
- progname, pid, packet->user,
- (packet->database[0] == '\0' ? packet->user : packet->database),
- port->sock);
+ fprintf(stderr, "%s: BackendStartup: pid %d user %s db %s socket %d\n",
+ progname, pid, packet->user,
+ (packet->database[0] == '\0' ? packet->user : packet->database),
+ port->sock);
/* adjust backend counter */
/* XXX Don't know why this is done, but for now backend needs it */
@@ -957,16 +1011,16 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
* list of backends.
*/
if (!(bn = (Backend *) calloc(1, sizeof (Backend)))) {
- fprintf(stderr, "%s: BackendStartup: malloc failed\n",
- progname);
- ExitPostmaster(1);
+ fprintf(stderr, "%s: BackendStartup: malloc failed\n",
+ progname);
+ ExitPostmaster(1);
}
bn->pid = pid;
DLAddHead(BackendList,DLNewElem(bn));
if (MultiplexedBackends)
- MultiplexedBackendPort++;
+ MultiplexedBackendPort++;
*pidPtr = pid;
@@ -986,17 +1040,17 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
static void
split_opts(char **argv, int *argcp, char *s)
{
- int i = *argcp;
+ int i = *argcp;
while (s && *s) {
- while (isspace(*s))
- ++s;
- if (*s)
- argv[i++] = s;
- while (*s && !isspace(*s))
- ++s;
- if (isspace(*s))
- *s++ = '\0';
+ while (isspace(*s))
+ ++s;
+ if (*s)
+ argv[i++] = s;
+ while (*s && !isspace(*s))
+ ++s;
+ if (isspace(*s))
+ *s++ = '\0';
}
*argcp = i;
}
@@ -1010,26 +1064,26 @@ split_opts(char **argv, int *argcp, char *s)
* fork() because we don't have vfork(), then we don't really care.)
*
* returns:
- * Shouldn't return at all.
- * If execv() fails, return status.
+ * Shouldn't return at all.
+ * If execv() fails, return status.
*/
static int
DoExec(StartupInfo *packet, int portFd)
{
- char execbuf[MAXPATHLEN];
- char portbuf[ARGV_SIZE];
+ char execbuf[MAXPATHLEN];
+ char portbuf[ARGV_SIZE];
char mbbuf[ARGV_SIZE];
- char debugbuf[ARGV_SIZE];
- char ttybuf[ARGV_SIZE + 1];
- char argbuf[(2 * ARGV_SIZE) + 1];
+ char debugbuf[ARGV_SIZE];
+ char ttybuf[ARGV_SIZE + 1];
+ char argbuf[(2 * ARGV_SIZE) + 1];
/*
* each argument takes at least three chars, so we can't
* have more than ARGV_SIZE arguments in (2 * ARGV_SIZE)
* chars (i.e., packet->options plus ExtraOptions)...
*/
- char *av[ARGV_SIZE];
- char dbbuf[ARGV_SIZE + 1];
- int ac = 0;
+ char *av[ARGV_SIZE];
+ char dbbuf[ARGV_SIZE + 1];
+ int ac = 0;
int i;
#if defined(WIN32)
char win32_args[(2 * ARGV_SIZE) + 1];
@@ -1054,16 +1108,16 @@ DoExec(StartupInfo *packet, int portFd)
*/
if (DebugLvl > 1) {
- (void) sprintf(debugbuf, "-d%d", DebugLvl - 1);
- av[ac++] = debugbuf;
+ (void) sprintf(debugbuf, "-d%d", DebugLvl - 1);
+ av[ac++] = debugbuf;
}
else
- av[ac++] = "-Q";
+ av[ac++] = "-Q";
/* Pass the requested debugging output file */
if (packet->tty[0]) {
- (void) strncpy(ttybuf, packet->tty, ARGV_SIZE);
- av[ac++] = "-o";
+ (void) strncpy(ttybuf, packet->tty, ARGV_SIZE);
+ av[ac++] = "-o";
#if defined(WIN32)
/* BIG HACK - The front end is passing "/dev/null" here which
** causes new backends to fail. So, as a very special case,
@@ -1092,20 +1146,20 @@ DoExec(StartupInfo *packet, int portFd)
split_opts(av, &ac, argbuf);
if (packet->database[0])
- (void) strncpy(dbbuf, packet->database, ARGV_SIZE);
+ (void) strncpy(dbbuf, packet->database, ARGV_SIZE);
else
- (void) strncpy(dbbuf, packet->user, NAMEDATALEN);
+ (void) strncpy(dbbuf, packet->user, NAMEDATALEN);
dbbuf[ARGV_SIZE] = '\0';
av[ac++] = dbbuf;
av[ac] = (char *) NULL;
if (DebugLvl > 1) {
- fprintf(stderr, "%s child[%ld]: execv(",
- progname, (long)getpid());
- for (i = 0; i < ac; ++i)
- fprintf(stderr, "%s, ", av[i]);
- fprintf(stderr, ")\n");
+ fprintf(stderr, "%s child[%ld]: execv(",
+ progname, (long)getpid());
+ for (i = 0; i < ac; ++i)
+ fprintf(stderr, "%s, ", av[i]);
+ fprintf(stderr, ")\n");
}
#ifndef WIN32
@@ -1156,7 +1210,7 @@ ExitPostmaster(int status)
* should the backends all be killed? probably not.
*/
if (ServerSock != INVALID_SOCK)
- close(ServerSock);
+ close(ServerSock);
exitpg(status);
}
@@ -1166,50 +1220,17 @@ dumpstatus(SIGNAL_ARGS)
Dlelem *curr = DLGetHead(PortList);
while (curr) {
- Port *port = DLE_VAL(curr);
-
- fprintf(stderr, "%s: dumpstatus:\n", progname);
- fprintf(stderr, "\tsock %d: nBytes=%d, laddr=0x%lx, raddr=0x%lx\n",
- port->sock, port->nBytes,
- (long int) port->laddr.sin_addr.s_addr,
- (long int) port->raddr.sin_addr.s_addr);
- curr = DLGetSucc(curr);
+ Port *port = DLE_VAL(curr);
+
+ fprintf(stderr, "%s: dumpstatus:\n", progname);
+ fprintf(stderr, "\tsock %d: nBytes=%d, laddr=0x%lx, raddr=0x%lx\n",
+ port->sock, port->nBytes,
+ (long int) port->laddr.sin_addr.s_addr,
+ (long int) port->raddr.sin_addr.s_addr);
+ curr = DLGetSucc(curr);
}
}
-static void
-checkDataDir(void)
-{
- char path[MAXPATHLEN];
- FILE *fp;
-
- sprintf(path, "%s%cbase%ctemplate1%cpg_class", DataDir, SEP_CHAR, SEP_CHAR,
- SEP_CHAR);
- if ((fp=fopen(path, "r")) == NULL) {
- fprintf(stderr, "%s does not find the database. Expected to find it "
- "in the PGDATA directory \"%s\", but unable to open file "
- "with pathname \"%s\".\n",
- progname, DataDir, path);
- exit(2);
- }
- fclose(fp);
-#ifndef WIN32
- {
- char *reason; /* reason ValidatePgVersion failed. NULL if didn't */
- ValidatePgVersion(DataDir, &reason);
- if (reason) {
- fprintf(stderr,
- "Database system in directory %s "
- "is not compatible with this version of "
- "Postgres, or we are unable to read the PG_VERSION file. "
- "Explanation from ValidatePgVersion: %s\n",
- DataDir, reason);
- free(reason);
- exit(2);
- }
- }
-#endif /* WIN32 */
-}