aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/pqcomm.c75
-rw-r--r--src/backend/postmaster/postmaster.c236
-rw-r--r--src/backend/tcop/postgres.c16
-rw-r--r--src/backend/utils/init/miscinit.c398
-rw-r--r--src/backend/utils/misc/guc.c4
-rwxr-xr-xsrc/bin/pg_ctl/pg_ctl.sh12
-rw-r--r--src/include/config.h.in5
-rw-r--r--src/include/miscadmin.h17
8 files changed, 373 insertions, 390 deletions
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index d680cfb7d51..35d6802a5a5 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -29,7 +29,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pqcomm.c,v 1.113 2000/11/21 23:03:53 petere Exp $
+ * $Id: pqcomm.c,v 1.114 2000/11/29 20:59:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -169,7 +169,7 @@ StreamDoUnlink(void)
/*
* StreamServerPort -- open a sock stream "listening" port.
*
- * This initializes the Postmaster's connection-accepting port fdP.
+ * This initializes the Postmaster's connection-accepting port *fdP.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/
@@ -183,9 +183,6 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
err;
size_t len = 0;
int one = 1;
-#ifdef HAVE_FCNTL_SETLK
- int lock_fd;
-#endif
Assert(family == AF_INET || family == AF_UNIX);
@@ -223,22 +220,15 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
len = UNIXSOCK_LEN(saddr.un);
strcpy(sock_path, saddr.un.sun_path);
/*
- * If the socket exists but nobody has an advisory lock on it we
- * can safely delete the file.
+ * Grab an interlock file associated with the socket file.
*/
-#ifdef HAVE_FCNTL_SETLK
- if ((lock_fd = open(sock_path, O_WRONLY | O_NONBLOCK | PG_BINARY, 0666)) >= 0)
- {
- struct flock lck;
-
- lck.l_whence = SEEK_SET;
- lck.l_start = lck.l_len = 0;
- lck.l_type = F_WRLCK;
- if (fcntl(lock_fd, F_SETLK, &lck) != -1)
- unlink(sock_path);
- close(lock_fd);
- }
-#endif /* HAVE_FCNTL_SETLK */
+ if (! CreateSocketLockFile(sock_path, true))
+ return STATUS_ERROR;
+ /*
+ * Once we have the interlock, we can safely delete any pre-existing
+ * socket file to avoid failure at bind() time.
+ */
+ unlink(sock_path);
}
#endif /* HAVE_UNIX_SOCKETS */
@@ -274,8 +264,8 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
{
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
"FATAL: StreamServerPort: bind() failed: %s\n"
- "\tIs another postmaster already running on that port?\n",
- strerror(errno));
+ "\tIs another postmaster already running on port %d?\n",
+ strerror(errno), (int) portNumber);
if (family == AF_UNIX)
snprintf(PQerrormsg + strlen(PQerrormsg),
PQERRORMSG_LENGTH - strlen(PQerrormsg),
@@ -293,41 +283,14 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
#ifdef HAVE_UNIX_SOCKETS
if (family == AF_UNIX)
{
+ /* Arrange to unlink the socket file at exit */
on_proc_exit(StreamDoUnlink, 0);
/*
- * Open the socket file and get an advisory lock on it. The
- * lock_fd is left open to keep the lock.
+ * Fix socket ownership/permission if requested. Note we must
+ * do this before we listen() to avoid a window where unwanted
+ * connections could get accepted.
*/
-#ifdef HAVE_FCNTL_SETLK
- if ((lock_fd = open(sock_path, O_WRONLY | O_NONBLOCK | PG_BINARY, 0666)) >= 0)
- {
- struct flock lck;
-
- lck.l_whence = SEEK_SET;
- lck.l_start = lck.l_len = 0;
- lck.l_type = F_WRLCK;
- if (fcntl(lock_fd, F_SETLK, &lck) != 0)
- elog(DEBUG, "flock error on %s: %s", sock_path, strerror(errno));
- }
-#endif /* HAVE_FCNTL_SETLK */
- }
-#endif /* HAVE_UNIX_SOCKETS */
-
- listen(fd, SOMAXCONN);
-
- /*
- * MS: I took this code from Dillon's version. It makes the listening
- * port non-blocking. That is not necessary (and may tickle kernel
- * bugs).
- *
- * fcntl(fd, F_SETFD, 1); fcntl(fd, F_SETFL, FNDELAY);
- */
-
- *fdP = fd;
-
- if (family == AF_UNIX)
- {
Assert(Unix_socket_group);
if (Unix_socket_group[0] != '\0')
{
@@ -379,6 +342,12 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
return STATUS_ERROR;
}
}
+#endif /* HAVE_UNIX_SOCKETS */
+
+ listen(fd, SOMAXCONN);
+
+ *fdP = fd;
+
return STATUS_OK;
}
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 9fa4ebb3689..80ff7bac3ea 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.194 2000/11/28 23:27:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.195 2000/11/29 20:59:52 tgl Exp $
*
* NOTES
*
@@ -104,8 +104,6 @@ typedef struct bkend
long cancel_key; /* cancel key for cancels for this backend */
} Backend;
-Port *MyBackendPort = NULL;
-
/* list of active backends. For garbage collection only now. */
static Dllist *BackendList;
@@ -114,8 +112,8 @@ static Dllist *PortList;
/* The socket number we are listening for connections on */
int PostPortNumber;
-char * UnixSocketDir;
-char * Virtual_host;
+char *UnixSocketDir;
+char *VirtualHost;
/*
* MaxBackends is the actual limit on the number of backends we will
@@ -216,6 +214,7 @@ static int BackendStartup(Port *port);
static int readStartupPacket(void *arg, PacketLen len, void *pkt);
static int processCancelRequest(Port *port, PacketLen len, void *pkt);
static int initMasks(fd_set *rmask, fd_set *wmask);
+static char *canAcceptConnections(void);
static long PostmasterRandom(void);
static void RandomSalt(char *salt);
static void SignalChildren(SIGNAL_ARGS);
@@ -252,7 +251,7 @@ checkDataDir(const char *checkdir)
"database system either by specifying the -D invocation "
"option or by setting the PGDATA environment variable.\n\n",
progname);
- exit(2);
+ ExitPostmaster(2);
}
snprintf(path, sizeof(path), "%s%cglobal%cpg_control",
@@ -265,7 +264,7 @@ checkDataDir(const char *checkdir)
"\n\tExpected to find it in the PGDATA directory \"%s\","
"\n\tbut unable to open file \"%s\": %s\n\n",
progname, checkdir, path, strerror(errno));
- exit(2);
+ ExitPostmaster(2);
}
FreeFile(fp);
@@ -299,12 +298,12 @@ PostmasterMain(int argc, char *argv[])
if (strcmp(argv[1], "--help")==0 || strcmp(argv[1], "-?")==0)
{
usage(progname);
- exit(0);
+ ExitPostmaster(0);
}
if (strcmp(argv[1], "--version")==0 || strcmp(argv[1], "-V")==0)
{
puts("postmaster (PostgreSQL) " PG_VERSION);
- exit(0);
+ ExitPostmaster(0);
}
}
@@ -367,7 +366,7 @@ PostmasterMain(int argc, char *argv[])
case '?':
fprintf(stderr, "Try '%s --help' for more information.\n", progname);
- exit(1);
+ ExitPostmaster(1);
}
}
@@ -378,7 +377,7 @@ PostmasterMain(int argc, char *argv[])
{
fprintf(stderr, "%s: invalid argument -- %s\n", progname, argv[optind]);
fprintf(stderr, "Try '%s --help' for more information.\n", progname);
- exit(1);
+ ExitPostmaster(1);
}
checkDataDir(potential_DataDir); /* issues error messages */
@@ -427,7 +426,7 @@ PostmasterMain(int argc, char *argv[])
enableFsync = false;
break;
case 'h':
- Virtual_host = optarg;
+ VirtualHost = optarg;
break;
case 'i':
NetServer = true;
@@ -525,7 +524,7 @@ PostmasterMain(int argc, char *argv[])
default:
/* shouldn't get here */
fprintf(stderr, "Try '%s --help' for more information.\n", progname);
- exit(1);
+ ExitPostmaster(1);
}
}
@@ -542,7 +541,7 @@ PostmasterMain(int argc, char *argv[])
*/
fprintf(stderr, "%s: The number of buffers (-B) must be at least twice the number of allowed connections (-N) and at least 16.\n",
progname);
- exit(1);
+ ExitPostmaster(1);
}
if (DebugLvl > 2)
@@ -559,6 +558,27 @@ PostmasterMain(int argc, char *argv[])
}
/*
+ * Fork away from controlling terminal, if -S specified.
+ *
+ * Must do this before we grab any interlock files, else the interlocks
+ * will show the wrong PID.
+ */
+ if (SilentMode)
+ pmdaemonize(argc, argv);
+
+ /*
+ * Create lockfile for data directory.
+ *
+ * We want to do this before we try to grab the input sockets, because
+ * the data directory interlock is more reliable than the socket-file
+ * interlock (thanks to whoever decided to put socket files in /tmp :-().
+ * For the same reason, it's best to grab the TCP socket before the
+ * Unix socket.
+ */
+ if (! CreateDataDirLockFile(DataDir, true))
+ ExitPostmaster(1);
+
+ /*
* Establish input sockets.
*/
#ifdef USE_SSL
@@ -566,7 +586,7 @@ PostmasterMain(int argc, char *argv[])
{
fprintf(stderr, "%s: For SSL, TCP/IP connections must be enabled. See -? for help.\n",
progname);
- exit(1);
+ ExitPostmaster(1);
}
if (EnableSSL)
InitSSL();
@@ -574,7 +594,7 @@ PostmasterMain(int argc, char *argv[])
if (NetServer)
{
- status = StreamServerPort(AF_INET, Virtual_host,
+ status = StreamServerPort(AF_INET, VirtualHost,
(unsigned short) PostPortNumber, UnixSocketDir,
&ServerSock_INET);
if (status != STATUS_OK)
@@ -586,7 +606,7 @@ PostmasterMain(int argc, char *argv[])
}
#ifdef HAVE_UNIX_SOCKETS
- status = StreamServerPort(AF_UNIX, Virtual_host,
+ status = StreamServerPort(AF_UNIX, VirtualHost,
(unsigned short) PostPortNumber, UnixSocketDir,
&ServerSock_UNIX);
if (status != STATUS_OK)
@@ -599,7 +619,9 @@ PostmasterMain(int argc, char *argv[])
XLOGPathInit();
- /* set up shared memory and semaphores */
+ /*
+ * Set up shared memory and semaphores.
+ */
reset_shared(PostPortNumber);
/*
@@ -609,35 +631,12 @@ PostmasterMain(int argc, char *argv[])
BackendList = DLNewList();
PortList = DLNewList();
- if (SilentMode)
- pmdaemonize(argc, argv);
- else
- {
-
- /*
- * create pid file. if the file has already existed, exits.
- */
- SetPidFname(DataDir);
- if (SetPidFile(getpid()) == 0)
- {
- if (!CreateOptsFile(argc, argv))
- {
- UnlinkPidFile();
- ExitPostmaster(1);
- return 0; /* not reached */
- }
- }
- else
- {
- ExitPostmaster(1);
- return 0; /* not reached */
- }
-
- /*
- * register clean up proc
- */
- on_proc_exit(UnlinkPidFile, 0);
- }
+ /*
+ * Record postmaster options. We delay this till now to avoid recording
+ * bogus options (eg, NBuffers too high for available memory).
+ */
+ if (!CreateOptsFile(argc, argv))
+ ExitPostmaster(1);
/*
* Set up signal handlers for the postmaster process.
@@ -658,11 +657,18 @@ PostmasterMain(int argc, char *argv[])
pqsignal(SIGTTOU, SIG_IGN); /* ignored */
pqsignal(SIGWINCH, dumpstatus); /* dump port status */
+ /*
+ * We're ready to rock and roll...
+ */
StartupPID = StartupDataBase();
status = ServerLoop();
+ /*
+ * ServerLoop probably shouldn't ever return, but if it does, close down.
+ */
ExitPostmaster(status != STATUS_OK);
+
return 0; /* not reached */
}
@@ -672,8 +678,6 @@ pmdaemonize(int argc, char *argv[])
int i;
pid_t pid;
- SetPidFname(DataDir);
-
pid = fork();
if (pid == -1)
{
@@ -683,36 +687,8 @@ pmdaemonize(int argc, char *argv[])
}
else if (pid)
{ /* parent */
-
- /*
- * create pid file. if the file has already existed, exits.
- */
- if (SetPidFile(pid) == 0)
- {
- if (!CreateOptsFile(argc, argv))
- {
-
- /*
- * Failed to create opts file. kill the child and exit
- * now.
- */
- UnlinkPidFile();
- kill(pid, SIGTERM);
- ExitPostmaster(1);
- return; /* not reached */
- }
- _exit(0);
- }
- else
- {
-
- /*
- * Failed to create pid file. kill the child and exit now.
- */
- kill(pid, SIGTERM);
- ExitPostmaster(1);
- return; /* not reached */
- }
+ /* Parent should just exit, without doing any atexit cleanup */
+ _exit(0);
}
/* GH: If there's no setsid(), we hopefully don't need silent mode.
@@ -723,7 +699,7 @@ pmdaemonize(int argc, char *argv[])
{
fprintf(stderr, "%s: ", progname);
perror("cannot disassociate from controlling TTY");
- exit(1);
+ ExitPostmaster(1);
}
#endif
i = open(NULL_DEV, O_RDWR | PG_BINARY);
@@ -731,11 +707,6 @@ pmdaemonize(int argc, char *argv[])
dup2(i, 1);
dup2(i, 2);
close(i);
-
- /*
- * register clean up proc
- */
- on_proc_exit(UnlinkPidFile, 0);
}
@@ -960,24 +931,19 @@ ServerLoop(void)
if (status == STATUS_OK && port->pktInfo.state == Idle)
{
-
/*
- * Can't start backend if max backend count is exceeded.
+ * Can we accept a connection now?
*
- * The same when data base is in startup/shutdown mode.
+ * Even though readStartupPacket() already checked,
+ * we have to check again in case conditions changed
+ * while negotiating authentication.
*/
- if (Shutdown > NoShutdown)
- PacketSendError(&port->pktInfo,
- "The Data Base System is shutting down");
- else if (StartupPID)
- PacketSendError(&port->pktInfo,
- "The Data Base System is starting up");
- else if (FatalError)
- PacketSendError(&port->pktInfo,
- "The Data Base System is in recovery mode");
- else if (CountChildren() >= MaxBackends)
- PacketSendError(&port->pktInfo,
- "Sorry, too many clients already");
+ char *rejectMsg = canAcceptConnections();
+
+ if (rejectMsg != NULL)
+ {
+ PacketSendError(&port->pktInfo, rejectMsg);
+ }
else
{
@@ -1066,6 +1032,7 @@ readStartupPacket(void *arg, PacketLen len, void *pkt)
{
Port *port;
StartupPacket *si;
+ char *rejectMsg;
port = (Port *) arg;
si = (StartupPacket *) pkt;
@@ -1158,6 +1125,19 @@ readStartupPacket(void *arg, PacketLen len, void *pkt)
return STATUS_OK; /* don't close the connection yet */
}
+ /*
+ * If we're going to reject the connection due to database state,
+ * say so now instead of wasting cycles on an authentication exchange.
+ * (This also allows a pg_ping utility to be written.)
+ */
+ rejectMsg = canAcceptConnections();
+
+ if (rejectMsg != NULL)
+ {
+ PacketSendError(&port->pktInfo, rejectMsg);
+ return STATUS_OK; /* don't close the connection yet */
+ }
+
/* Start the authentication itself. */
be_recvauth(port);
@@ -1226,6 +1206,28 @@ processCancelRequest(Port *port, PacketLen len, void *pkt)
return STATUS_ERROR;
}
+/*
+ * canAcceptConnections --- check to see if database state allows connections.
+ *
+ * If we are open for business, return NULL, otherwise return an error message
+ * string suitable for rejecting a connection request.
+ */
+static char *
+canAcceptConnections(void)
+{
+ /* Can't start backends when in startup/shutdown/recovery state. */
+ if (Shutdown > NoShutdown)
+ return "The Data Base System is shutting down";
+ if (StartupPID)
+ return "The Data Base System is starting up";
+ if (FatalError)
+ return "The Data Base System is in recovery mode";
+ /* Can't start backend if max backend count is exceeded. */
+ if (CountChildren() >= MaxBackends)
+ return "Sorry, too many clients already";
+
+ return NULL;
+}
/*
* ConnCreate -- create a local connection data structure
@@ -1423,7 +1425,7 @@ pmdie(SIGNAL_ARGS)
}
/* exit postmaster */
- proc_exit(0);
+ ExitPostmaster(0);
}
/*
@@ -1465,9 +1467,9 @@ reaper(SIGNAL_ARGS)
{
fprintf(stderr, "Shutdown failed - abort\n");
fflush(stderr);
- proc_exit(1);
+ ExitPostmaster(1);
}
- proc_exit(0);
+ ExitPostmaster(0);
}
if (StartupPID > 0)
{
@@ -1477,7 +1479,7 @@ reaper(SIGNAL_ARGS)
{
fprintf(stderr, "Startup failed - abort\n");
fflush(stderr);
- proc_exit(1);
+ ExitPostmaster(1);
}
StartupPID = 0;
FatalError = false;
@@ -1507,7 +1509,7 @@ reaper(SIGNAL_ARGS)
{
/*
- * Wait for all children exit then StartupDataBase.
+ * Wait for all children exit, then reset shmem and StartupDataBase.
*/
if (DLGetHead(BackendList))
return;
@@ -1518,8 +1520,10 @@ reaper(SIGNAL_ARGS)
"Reinitializing shared memory and semaphores\n",
ctime(&tnow));
fflush(stderr);
+
shmem_exit(0);
reset_shared(PostPortNumber);
+
StartupPID = StartupDataBase();
return;
}
@@ -1744,10 +1748,10 @@ BackendStartup(Port *port)
{
fprintf(stderr, "%s child[%d]: BackendStartup: backend startup failed\n",
progname, (int) getpid());
- exit(1);
+ ExitPostmaster(1);
}
else
- exit(0);
+ ExitPostmaster(0);
}
/* in parent */
@@ -1943,9 +1947,9 @@ DoBackend(Port *port)
/*
* Release postmaster's working memory context so that backend can
- * recycle the space. Note we couldn't do it earlier than here,
- * because port pointer is pointing into that space! But now we
- * have copied all the interesting info into safe local storage.
+ * recycle the space. Note this does not trash *MyProcPort, because
+ * ConnCreate() allocated that space with malloc() ... else we'd need
+ * to copy the Port data here.
*/
MemoryContextSwitchTo(TopMemoryContext);
MemoryContextDelete(PostmasterContext);
@@ -1968,6 +1972,8 @@ DoBackend(Port *port)
/*
* ExitPostmaster -- cleanup
+ *
+ * Do NOT call exit() directly --- always go through here!
*/
static void
ExitPostmaster(int status)
@@ -2099,24 +2105,24 @@ InitSSL(void)
if (!SSL_context)
{
fprintf(stderr, "Failed to create SSL context: %s\n", ERR_reason_error_string(ERR_get_error()));
- exit(1);
+ ExitPostmaster(1);
}
snprintf(fnbuf, sizeof(fnbuf), "%s/server.crt", DataDir);
if (!SSL_CTX_use_certificate_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
{
fprintf(stderr, "Failed to load server certificate (%s): %s\n", fnbuf, ERR_reason_error_string(ERR_get_error()));
- exit(1);
+ ExitPostmaster(1);
}
snprintf(fnbuf, sizeof(fnbuf), "%s/server.key", DataDir);
if (!SSL_CTX_use_PrivateKey_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
{
fprintf(stderr, "Failed to load private key file (%s): %s\n", fnbuf, ERR_reason_error_string(ERR_get_error()));
- exit(1);
+ ExitPostmaster(1);
}
if (!SSL_CTX_check_private_key(SSL_context))
{
fprintf(stderr, "Check of private key failed: %s\n", ERR_reason_error_string(ERR_get_error()));
- exit(1);
+ ExitPostmaster(1);
}
}
@@ -2178,7 +2184,7 @@ SSDataBase(int xlop)
PG_SETMASK(&BlockSig);
BootstrapMain(ac, av);
- exit(0);
+ ExitPostmaster(0);
}
/* in parent */
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 0f8dec00d89..7d143a9590a 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.191 2000/11/25 20:33:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.192 2000/11/29 20:59:52 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1514,16 +1514,10 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
}
/*
- * Try to create pid file.
+ * Create lockfile for data directory.
*/
- SetPidFname(DataDir);
- if (SetPidFile(-getpid()))
- proc_exit(0);
-
- /*
- * Register clean up proc.
- */
- on_proc_exit(UnlinkPidFile, 0);
+ if (! CreateDataDirLockFile(DataDir, false))
+ proc_exit(1);
XLOGPathInit();
BaseInit();
@@ -1635,7 +1629,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.191 $ $Date: 2000/11/25 20:33:52 $\n");
+ puts("$Revision: 1.192 $ $Date: 2000/11/29 20:59:52 $\n");
}
/*
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 919a9dd220f..98af889946f 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* miscinit.c
- * miscellanious initialization support stuff
+ * miscellaneous initialization support stuff
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.58 2000/11/17 01:24:46 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.59 2000/11/29 20:59:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,8 +32,6 @@
#include "utils/builtins.h"
#include "utils/syscache.h"
-static char *GetPidFname(void);
-
#ifdef CYR_RECODE
unsigned char RecodeForwTable[128];
@@ -43,6 +41,7 @@ unsigned char RecodeBackTable[128];
ProcessingMode Mode = InitProcessing;
+
/* ----------------------------------------------------------------
* ignoring system indexes support stuff
* ----------------------------------------------------------------
@@ -99,11 +98,71 @@ SetDatabaseName(const char *name)
}
}
-#ifndef MULTIBYTE
-/* even if MULTIBYTE is not enabled, these functions are necessary
+/*
+ * Set data directory, but make sure it's an absolute path. Use this,
+ * never set DataDir directly.
+ */
+void
+SetDataDir(const char *dir)
+{
+ char *new;
+
+ AssertArg(dir);
+ if (DataDir)
+ free(DataDir);
+
+ if (dir[0] != '/')
+ {
+ char *buf;
+ size_t buflen;
+
+ buflen = MAXPGPATH;
+ for (;;)
+ {
+ buf = malloc(buflen);
+ if (!buf)
+ elog(FATAL, "out of memory");
+
+ if (getcwd(buf, buflen))
+ break;
+ else if (errno == ERANGE)
+ {
+ free(buf);
+ buflen *= 2;
+ continue;
+ }
+ else
+ {
+ free(buf);
+ elog(FATAL, "cannot get current working directory: %m");
+ }
+ }
+
+ new = malloc(strlen(buf) + 1 + strlen(dir) + 1);
+ sprintf(new, "%s/%s", buf, dir);
+ free(buf);
+ }
+ else
+ {
+ new = strdup(dir);
+ }
+
+ if (!new)
+ elog(FATAL, "out of memory");
+ DataDir = new;
+}
+
+
+/* ----------------------------------------------------------------
+ * MULTIBYTE stub code
+ *
+ * Even if MULTIBYTE is not enabled, these functions are necessary
* since pg_proc.h has references to them.
+ * ----------------------------------------------------------------
*/
+#ifndef MULTIBYTE
+
Datum
getdatabaseencoding(PG_FUNCTION_ARGS)
{
@@ -124,7 +183,13 @@ PG_char_to_encoding(PG_FUNCTION_ARGS)
#endif
+/* ----------------------------------------------------------------
+ * CYR_RECODE support
+ * ----------------------------------------------------------------
+ */
+
#ifdef CYR_RECODE
+
#define MAX_TOKEN 80
/* Some standard C libraries, including GNU, have an isblank() function.
@@ -376,228 +441,189 @@ GetUserName(Oid userid)
/*-------------------------------------------------------------------------
- * Set data directory, but make sure it's an absolute path. Use this,
- * never set DataDir directly.
- *-------------------------------------------------------------------------
- */
-void
-SetDataDir(const char *dir)
-{
- char *new;
-
- AssertArg(dir);
- if (DataDir)
- free(DataDir);
-
- if (dir[0] != '/')
- {
- char *buf;
- size_t buflen;
-
- buflen = MAXPGPATH;
- for (;;)
- {
- buf = malloc(buflen);
- if (!buf)
- elog(FATAL, "out of memory");
-
- if (getcwd(buf, buflen))
- break;
- else if (errno == ERANGE)
- {
- free(buf);
- buflen *= 2;
- continue;
- }
- else
- {
- free(buf);
- elog(FATAL, "cannot get current working directory: %m");
- }
- }
-
- new = malloc(strlen(buf) + 1 + strlen(dir) + 1);
- sprintf(new, "%s/%s", buf, dir);
- }
- else
- {
- new = strdup(dir);
- }
-
- if (!new)
- elog(FATAL, "out of memory");
- DataDir = new;
-}
-
-
-
-/*-------------------------------------------------------------------------
+ * Interlock-file support
*
- * postmaster pid file stuffs. $DATADIR/postmaster.pid is created when:
+ * These routines are used to create both a data-directory lockfile
+ * ($DATADIR/postmaster.pid) and a Unix-socket-file lockfile ($SOCKFILE.lock).
+ * Both kinds of files contain the same info:
*
- * (1) postmaster starts. In this case pid > 0.
- * (2) postgres starts in standalone mode. In this case
- * pid < 0
+ * Owning process' PID
+ * Data directory path
*
- * to gain an interlock.
- *
- * SetPidFname(datadir)
- * Remember the the pid file name. This is neccesary
- * UnlinkPidFile() is called from proc_exit().
- *
- * GetPidFname(datadir)
- * Get the pid file name. SetPidFname() should be called
- * before GetPidFname() gets called.
- *
- * UnlinkPidFile()
- * This is called from proc_exit() and unlink the pid file.
- *
- * SetPidFile(pid_t pid)
- * Create the pid file. On failure, it checks if the process
- * actually exists or not. SetPidFname() should be called
- * in prior to calling SetPidFile().
+ * By convention, the owning process' PID is negated if it is a standalone
+ * backend rather than a postmaster. This is just for informational purposes.
+ * The path is also just for informational purposes (so that a socket lockfile
+ * can be more easily traced to the associated postmaster).
*
+ * On successful lockfile creation, a proc_exit callback to remove the
+ * lockfile is automatically created.
*-------------------------------------------------------------------------
*/
/*
- * Path to pid file. proc_exit() remember it to unlink the file.
- */
-static char PidFile[MAXPGPATH];
-
-/*
- * Remove the pid file. This function is called from proc_exit.
- */
-void
-UnlinkPidFile(void)
-{
- unlink(PidFile);
-}
-
-/*
- * Set path to the pid file
- */
-void
-SetPidFname(char *datadir)
-{
- snprintf(PidFile, sizeof(PidFile), "%s/%s", datadir, PIDFNAME);
-}
-
-/*
- * Get path to the pid file
+ * proc_exit callback to remove a lockfile.
*/
-static char *
-GetPidFname(void)
+static void
+UnlinkLockFile(int status, Datum filename)
{
- return (PidFile);
+ unlink((char *) DatumGetPointer(filename));
+ /* Should we complain if the unlink fails? */
}
/*
- * Create the pid file
+ * Create a lockfile, if possible
+ *
+ * Call CreateLockFile with the name of the lockfile to be created. If
+ * successful, it returns zero. On detecting a collision, it returns
+ * the PID or negated PID of the lockfile owner --- the caller is responsible
+ * for producing an appropriate error message.
*/
-int
-SetPidFile(pid_t pid)
+static int
+CreateLockFile(const char *filename, bool amPostmaster)
{
int fd;
- char *pidfile;
- char pidstr[32];
+ char buffer[MAXPGPATH + 32];
int len;
- pid_t post_pid;
- int is_postgres = 0;
+ int encoded_pid;
+ pid_t other_pid;
+ pid_t my_pid = getpid();
/*
- * Creating pid file
+ * We need a loop here because of race conditions.
*/
- pidfile = GetPidFname();
- fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
- if (fd < 0)
+ for (;;)
{
+ /*
+ * Try to create the lock file --- O_EXCL makes this atomic.
+ */
+ fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
+ if (fd >= 0)
+ break; /* Success; exit the retry loop */
+ /*
+ * Couldn't create the pid file. Probably it already exists.
+ */
+ if (errno != EEXIST && errno != EACCES)
+ elog(FATAL, "Can't create lock file %s: %m", filename);
/*
- * Couldn't create the pid file. Probably it already exists. Read
- * the file to see if the process actually exists
+ * Read the file to get the old owner's PID. Note race condition
+ * here: file might have been deleted since we tried to create it.
*/
- fd = open(pidfile, O_RDONLY, 0600);
+ fd = open(filename, O_RDONLY, 0600);
if (fd < 0)
{
- fprintf(stderr, "Can't open pid file: %s\n", pidfile);
- fprintf(stderr, "Please check the permission and try again.\n");
- return (-1);
- }
- if ((len = read(fd, pidstr, sizeof(pidstr) - 1)) < 0)
- {
- fprintf(stderr, "Can't read pid file: %s\n", pidfile);
- fprintf(stderr, "Please check the permission and try again.\n");
- close(fd);
- return (-1);
+ if (errno == ENOENT)
+ continue; /* race condition; try again */
+ elog(FATAL, "Can't read lock file %s: %m", filename);
}
+ if ((len = read(fd, buffer, sizeof(buffer) - 1)) <= 0)
+ elog(FATAL, "Can't read lock file %s: %m", filename);
close(fd);
- /*
- * Check to see if the process actually exists
- */
- pidstr[len] = '\0';
- post_pid = (pid_t) atoi(pidstr);
+ buffer[len] = '\0';
+ encoded_pid = atoi(buffer);
- /* if pid < 0, the pid is for postgres, not postmatser */
- if (post_pid < 0)
- {
- is_postgres++;
- post_pid = -post_pid;
- }
+ /* if pid < 0, the pid is for postgres, not postmaster */
+ other_pid = (pid_t) (encoded_pid < 0 ? -encoded_pid : encoded_pid);
- if (post_pid == 0 || (post_pid > 0 && kill(post_pid, 0) < 0))
- {
+ if (other_pid <= 0)
+ elog(FATAL, "Bogus data in lock file %s", filename);
- /*
- * No, the process did not exist. Unlink the file and try to
- * create it
- */
- if (unlink(pidfile) < 0)
- {
- fprintf(stderr, "Can't remove pid file: %s\n", pidfile);
- fprintf(stderr, "The file seems accidently left, but I couldn't remove it.\n");
- fprintf(stderr, "Please remove the file by hand and try again.\n");
- return (-1);
- }
- fd = open(pidfile, O_RDWR | O_CREAT | O_EXCL, 0600);
- if (fd < 0)
- {
- fprintf(stderr, "Can't create pid file: %s\n", pidfile);
- fprintf(stderr, "Please check the permission and try again.\n");
- return (-1);
- }
- }
- else
+ /*
+ * Check to see if the other process still exists
+ */
+ if (other_pid != my_pid)
{
-
- /*
- * Another postmaster is running
- */
- fprintf(stderr, "Can't create pid file: %s\n", pidfile);
- if (is_postgres)
- fprintf(stderr, "Is another postgres (pid: %d) running?\n", (int) post_pid);
- else
- fprintf(stderr, "Is another postmaster (pid: %s) running?\n", pidstr);
- return (-1);
+ if (kill(other_pid, 0) == 0 ||
+ errno != ESRCH)
+ return encoded_pid; /* lockfile belongs to a live process */
}
+
+ /*
+ * No, the process did not exist. Unlink the file and try again to
+ * create it. Need a loop because of possible race condition against
+ * other would-be creators.
+ */
+ if (unlink(filename) < 0)
+ elog(FATAL, "Can't remove old lock file %s: %m"
+ "\n\tThe file seems accidentally left, but I couldn't remove it."
+ "\n\tPlease remove the file by hand and try again.",
+ filename);
}
- sprintf(pidstr, "%d", (int) pid);
- if (write(fd, pidstr, strlen(pidstr)) != strlen(pidstr))
+ /*
+ * Successfully created the file, now fill it.
+ */
+ snprintf(buffer, sizeof(buffer), "%d\n%s\n",
+ amPostmaster ? (int) my_pid : - ((int) my_pid),
+ DataDir);
+ if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
{
- fprintf(stderr, "Write to pid file failed\n");
- fprintf(stderr, "Please check the permission and try again.\n");
+ int save_errno = errno;
+
close(fd);
- unlink(pidfile);
- return (-1);
+ unlink(filename);
+ errno = save_errno;
+ elog(FATAL, "Can't write lock file %s: %m", filename);
}
close(fd);
- return (0);
+ /*
+ * Arrange for automatic removal of lockfile at proc_exit.
+ */
+ on_proc_exit(UnlinkLockFile, PointerGetDatum(strdup(filename)));
+
+ return 0; /* Success! */
+}
+
+bool
+CreateDataDirLockFile(const char *datadir, bool amPostmaster)
+{
+ char lockfile[MAXPGPATH];
+ int encoded_pid;
+
+ snprintf(lockfile, sizeof(lockfile), "%s/postmaster.pid", datadir);
+ encoded_pid = CreateLockFile(lockfile, amPostmaster);
+ if (encoded_pid != 0)
+ {
+ fprintf(stderr, "Lock file \"%s\" already exists.\n", lockfile);
+ if (encoded_pid < 0)
+ fprintf(stderr, "Is another postgres (pid %d) running in \"%s\"?\n",
+ -encoded_pid, datadir);
+ else
+ fprintf(stderr, "Is another postmaster (pid %d) running in \"%s\"?\n",
+ encoded_pid, datadir);
+ return false;
+ }
+ return true;
}
+bool
+CreateSocketLockFile(const char *socketfile, bool amPostmaster)
+{
+ char lockfile[MAXPGPATH];
+ int encoded_pid;
+
+ snprintf(lockfile, sizeof(lockfile), "%s.lock", socketfile);
+ encoded_pid = CreateLockFile(lockfile, amPostmaster);
+ if (encoded_pid != 0)
+ {
+ fprintf(stderr, "Lock file \"%s\" already exists.\n", lockfile);
+ if (encoded_pid < 0)
+ fprintf(stderr, "Is another postgres (pid %d) using \"%s\"?\n",
+ -encoded_pid, socketfile);
+ else
+ fprintf(stderr, "Is another postmaster (pid %d) using \"%s\"?\n",
+ encoded_pid, socketfile);
+ return false;
+ }
+ return true;
+}
+/*-------------------------------------------------------------------------
+ * Version checking support
+ *-------------------------------------------------------------------------
+ */
/*
* Determine whether the PG_VERSION file in directory `path' indicates
@@ -628,12 +654,12 @@ ValidatePgVersion(const char *path)
if (errno == ENOENT)
elog(FATAL, "File %s is missing. This is not a valid data directory.", full_path);
else
- elog(FATAL, "cannot open %s: %s", full_path, strerror(errno));
+ elog(FATAL, "cannot open %s: %m", full_path);
}
ret = fscanf(file, "%ld.%ld", &file_major, &file_minor);
if (ret == EOF)
- elog(FATAL, "cannot read %s: %s", full_path, strerror(errno));
+ elog(FATAL, "cannot read %s: %m", full_path);
else if (ret != 2)
elog(FATAL, "`%s' does not have a valid format. You need to initdb.", full_path);
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 7813b6d10ba..398fb25bf68 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -4,7 +4,7 @@
* Support for grand unified configuration scheme, including SET
* command, configuration file, and command line options.
*
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.23 2000/11/25 04:13:17 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.24 2000/11/29 20:59:53 tgl Exp $
*
* Copyright 2000 by PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -319,7 +319,7 @@ ConfigureNamesString[] =
{"unix_socket_directory", PGC_POSTMASTER, &UnixSocketDir,
"", NULL},
- {"virtual_host", PGC_POSTMASTER, &Virtual_host,
+ {"virtual_host", PGC_POSTMASTER, &VirtualHost,
"", NULL},
{NULL, 0, NULL, NULL, NULL}
diff --git a/src/bin/pg_ctl/pg_ctl.sh b/src/bin/pg_ctl/pg_ctl.sh
index ae7a1c19a02..6802269befb 100755
--- a/src/bin/pg_ctl/pg_ctl.sh
+++ b/src/bin/pg_ctl/pg_ctl.sh
@@ -8,7 +8,7 @@
#
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/bin/pg_ctl/Attic/pg_ctl.sh,v 1.15 2000/11/27 02:50:17 tgl Exp $
+# $Header: /cvsroot/pgsql/src/bin/pg_ctl/Attic/pg_ctl.sh,v 1.16 2000/11/29 20:59:53 tgl Exp $
#
#-------------------------------------------------------------------------
@@ -187,7 +187,7 @@ PIDFILE=$PGDATA/postmaster.pid
if [ $op = "status" ];then
if [ -f $PIDFILE ];then
- PID=`cat $PIDFILE`
+ PID=`head -1 $PIDFILE`
if [ $PID -lt 0 ];then
PID=`expr 0 - $PID`
echo "$CMDNAME: postgres is running (pid: $PID)"
@@ -205,7 +205,7 @@ fi
if [ $op = "stop" -o $op = "restart" ];then
if [ -f $PIDFILE ];then
- PID=`cat $PIDFILE`
+ PID=`head -1 $PIDFILE`
if [ $PID -lt 0 ];then
PID=`expr 0 - $PID`
echo "$CMDNAME: Cannot restart postmaster. postgres is running (pid: $PID)"
@@ -213,7 +213,7 @@ if [ $op = "stop" -o $op = "restart" ];then
exit 1
fi
- kill $sig `cat $PIDFILE`
+ kill $sig $PID
# wait for postmaster shutting down
if [ "$wait" = 1 -o $op = "restart" ];then
@@ -253,7 +253,7 @@ fi
if [ $op = "start" -o $op = "restart" ];then
if [ -f $PIDFILE ];then
echo "$CMDNAME: It seems another postmaster is running. Trying to start postmaster anyway."
- pid=`cat $PIDFILE`
+ pid=`head -1 $PIDFILE`
fi
# no -o given
@@ -275,7 +275,7 @@ if [ $op = "start" -o $op = "restart" ];then
fi
if [ -f $PIDFILE ];then
- if [ "`cat $PIDFILE`" = "$pid" ];then
+ if [ "`head -1 $PIDFILE`" = "$pid" ];then
echo "$CMDNAME: Cannot start postmaster. Is another postmaster is running?"
exit 1
fi
diff --git a/src/include/config.h.in b/src/include/config.h.in
index ab699b30f3c..1f6939dd960 100644
--- a/src/include/config.h.in
+++ b/src/include/config.h.in
@@ -8,7 +8,7 @@
* or in config.h afterwards. Of course, if you edit config.h, then your
* changes will be overwritten the next time you run configure.
*
- * $Id: config.h.in,v 1.149 2000/11/20 16:52:54 petere Exp $
+ * $Id: config.h.in,v 1.150 2000/11/29 20:59:54 tgl Exp $
*/
#ifndef CONFIG_H
@@ -567,9 +567,6 @@ extern void srandom(unsigned int seed);
/* Set to 1 if you have struct sockaddr_un */
#undef HAVE_STRUCT_SOCKADDR_UN
-/* Set to 1 if you have F_SETLK option for fcntl() */
-#undef HAVE_FCNTL_SETLK
-
/* Set to 1 if type "long int" works and is 64 bits */
#undef HAVE_LONG_INT_64
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index cff6439dde3..f41a01822ac 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: miscadmin.h,v 1.74 2000/11/25 22:34:13 momjian Exp $
+ * $Id: miscadmin.h,v 1.75 2000/11/29 20:59:54 tgl Exp $
*
* NOTES
* some of the information in this file will be moved to
@@ -114,7 +114,7 @@ extern int PostPortNumber;
extern int Unix_socket_permissions;
extern char *Unix_socket_group;
extern char *UnixSocketDir;
-extern char *Virtual_host;
+extern char *VirtualHost;
/*****************************************************************************
@@ -227,17 +227,8 @@ extern bool IsIgnoringSystemIndexes(void);
extern bool IsCacheInitialized(void);
extern void SetWaitingForLock(bool);
-/*
- * "postmaster.pid" is a file containing postmaster's pid, being
- * created uder $PGDATA upon postmaster's starting up. When postmaster
- * shuts down, it will be unlinked.
-*/
-#define PIDFNAME "postmaster.pid"
-
-extern void SetPidFname(char *datadir);
-extern void UnlinkPidFile(void);
-extern int SetPidFile(pid_t pid);
-
+extern bool CreateDataDirLockFile(const char *datadir, bool amPostmaster);
+extern bool CreateSocketLockFile(const char *socketfile, bool amPostmaster);
extern void ValidatePgVersion(const char *path);