START_COMMAND,
STOP_COMMAND,
RESTART_COMMAND,
- PROMOTE_COMMAND,
RELOAD_COMMAND,
STATUS_COMMAND,
+ PROMOTE_COMMAND,
KILL_COMMAND,
REGISTER_COMMAND,
UNREGISTER_COMMAND,
write_stderr(const char *fmt,...)
/* This extension allows gcc to check the format string for consistency with
the supplied arguments. */
-__attribute__((format(printf, 1, 2)));
+__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
static void *pg_malloc(size_t size);
static char *xstrdup(const char *s);
static void do_advice(void);
static void do_start(void);
static void do_stop(void);
static void do_restart(void);
-static void do_promote(void);
static void do_reload(void);
static void do_status(void);
+static void do_promote(void);
static void do_kill(pgpid_t pid);
static void print_msg(const char *msg);
{
static HANDLE evtHandle = INVALID_HANDLE_VALUE;
+ if (silent_mode && level == EVENTLOG_INFORMATION_TYPE)
+ return;
+
if (evtHandle == INVALID_HANDLE_VALUE)
{
evtHandle = RegisterEventSource(NULL, "PostgreSQL");
/*
* Since there might be quotes to handle here, it is easier simply to pass
* everything to a shell to process them.
+ *
+ * XXX it would be better to fork and exec so that we would know the child
+ * postmaster's PID directly; then test_postmaster_connection could use
+ * the PID without having to rely on reading it back from the pidfile.
*/
if (log_file != NULL)
snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &" SYSTEMQUOTE,
static PGPing
test_postmaster_connection(bool do_checkpoint)
{
- PGPing ret = PQPING_OK; /* assume success for wait == zero */
+ PGPing ret = PQPING_NO_RESPONSE;
+ bool found_stale_pidfile = false;
+ pgpid_t pm_pid = 0;
char connstr[MAXPGPATH * 2 + 256];
int i;
+ /* if requested wait time is zero, return "still starting up" code */
+ if (wait_seconds <= 0)
+ return PQPING_REJECT;
+
connstr[0] = '\0';
for (i = 0; i < wait_seconds; i++)
if (optlines[3] == NULL)
{
/* File is exactly three lines, must be pre-9.1 */
- write_stderr(_("%s: -w option is not supported when starting a pre-9.1 server\n"),
+ write_stderr(_("\n%s: -w option is not supported when starting a pre-9.1 server\n"),
progname);
return PQPING_NO_ATTEMPT;
}
optlines[5] != NULL)
{
/* File is complete enough for us, parse it */
+ long pmpid;
time_t pmstart;
- int portnum;
- char *sockdir;
- char *hostaddr;
- char host_str[MAXPGPATH];
/*
- * Easy cross-check that we are looking at the right data
- * directory: is the postmaster older than this execution
- * of pg_ctl? Subtract 2 seconds to allow for possible
- * clock skew between pg_ctl and the postmaster.
+ * Make sanity checks. If it's for a standalone backend
+ * (negative PID), or the recorded start time is before
+ * pg_ctl started, then either we are looking at the wrong
+ * data directory, or this is a pre-existing pidfile that
+ * hasn't (yet?) been overwritten by our child postmaster.
+ * Allow 2 seconds slop for possible cross-process clock
+ * skew.
*/
+ pmpid = atol(optlines[LOCK_FILE_LINE_PID - 1]);
pmstart = atol(optlines[LOCK_FILE_LINE_START_TIME - 1]);
- if (pmstart < start_time - 2)
+ if (pmpid <= 0 || pmstart < start_time - 2)
{
- write_stderr(_("%s: this data directory is running a pre-existing postmaster\n"),
- progname);
- return PQPING_NO_ATTEMPT;
+ /*
+ * Set flag to report stale pidfile if it doesn't get
+ * overwritten before we give up waiting.
+ */
+ found_stale_pidfile = true;
}
+ else
+ {
+ /*
+ * OK, seems to be a valid pidfile from our child.
+ */
+ int portnum;
+ char *sockdir;
+ char *hostaddr;
+ char host_str[MAXPGPATH];
- /*
- * OK, extract port number and host string to use. Prefer
- * using Unix socket if available.
- */
- portnum = atoi(optlines[LOCK_FILE_LINE_PORT - 1]);
+ found_stale_pidfile = false;
+ pm_pid = (pgpid_t) pmpid;
- sockdir = optlines[LOCK_FILE_LINE_SOCKET_DIR - 1];
- hostaddr = optlines[LOCK_FILE_LINE_LISTEN_ADDR - 1];
+ /*
+ * Extract port number and host string to use. Prefer
+ * using Unix socket if available.
+ */
+ portnum = atoi(optlines[LOCK_FILE_LINE_PORT - 1]);
+ sockdir = optlines[LOCK_FILE_LINE_SOCKET_DIR - 1];
+ hostaddr = optlines[LOCK_FILE_LINE_LISTEN_ADDR - 1];
- /*
- * While unix_socket_directory can accept relative
- * directories, libpq's host parameter must have a leading
- * slash to indicate a socket directory. So, ignore
- * sockdir if it's relative, and try to use TCP instead.
- */
- if (sockdir[0] == '/')
- strlcpy(host_str, sockdir, sizeof(host_str));
- else
- strlcpy(host_str, hostaddr, sizeof(host_str));
+ /*
+ * While unix_socket_directory can accept relative
+ * directories, libpq's host parameter must have a
+ * leading slash to indicate a socket directory. So,
+ * ignore sockdir if it's relative, and try to use TCP
+ * instead.
+ */
+ if (sockdir[0] == '/')
+ strlcpy(host_str, sockdir, sizeof(host_str));
+ else
+ strlcpy(host_str, hostaddr, sizeof(host_str));
- /* remove trailing newline */
- if (strchr(host_str, '\n') != NULL)
- *strchr(host_str, '\n') = '\0';
+ /* remove trailing newline */
+ if (strchr(host_str, '\n') != NULL)
+ *strchr(host_str, '\n') = '\0';
- /* Fail if we couldn't get either sockdir or host addr */
- if (host_str[0] == '\0')
- {
- write_stderr(_("%s: -w option cannot use a relative socket directory specification\n"),
- progname);
- return PQPING_NO_ATTEMPT;
- }
+ /* Fail if couldn't get either sockdir or host addr */
+ if (host_str[0] == '\0')
+ {
+ write_stderr(_("\n%s: -w option cannot use a relative socket directory specification\n"),
+ progname);
+ return PQPING_NO_ATTEMPT;
+ }
- /* If postmaster is listening on "*", use "localhost" */
- if (strcmp(host_str, "*") == 0)
- strcpy(host_str, "localhost");
+ /* If postmaster is listening on "*", use localhost */
+ if (strcmp(host_str, "*") == 0)
+ strcpy(host_str, "localhost");
- /*
- * We need to set connect_timeout otherwise on Windows the
- * Service Control Manager (SCM) will probably timeout
- * first.
- */
- snprintf(connstr, sizeof(connstr),
- "dbname=postgres port=%d host='%s' connect_timeout=5",
- portnum, host_str);
+ /*
+ * We need to set connect_timeout otherwise on Windows
+ * the Service Control Manager (SCM) will probably
+ * timeout first.
+ */
+ snprintf(connstr, sizeof(connstr),
+ "dbname=postgres port=%d host='%s' connect_timeout=5",
+ portnum, host_str);
+ }
}
}
}
break;
}
+ /*
+ * The postmaster should create postmaster.pid very soon after being
+ * started. If it's not there after we've waited 5 or more seconds,
+ * assume startup failed and give up waiting. (Note this covers both
+ * cases where the pidfile was never created, and where it was created
+ * and then removed during postmaster exit.) Also, if there *is* a
+ * file there but it appears stale, issue a suitable warning and give
+ * up waiting.
+ */
+ if (i >= 5)
+ {
+ struct stat statbuf;
+
+ if (stat(pid_file, &statbuf) != 0)
+ return PQPING_NO_RESPONSE;
+
+ if (found_stale_pidfile)
+ {
+ write_stderr(_("\n%s: this data directory appears to be running a pre-existing postmaster\n"),
+ progname);
+ return PQPING_NO_RESPONSE;
+ }
+ }
+
+ /*
+ * If we've been able to identify the child postmaster's PID, check
+ * the process is still alive. This covers cases where the postmaster
+ * successfully created the pidfile but then crashed without removing
+ * it.
+ */
+ if (pm_pid > 0 && !postmaster_is_alive((pid_t) pm_pid))
+ return PQPING_NO_RESPONSE;
+
/* No response, or startup still in process; wait */
#if defined(WIN32)
if (do_checkpoint)
static void
do_start(void)
{
- pgpid_t pid;
pgpid_t old_pid = 0;
int exitcode;
exit(1);
}
- if (old_pid != 0)
- {
- pg_usleep(1000000);
- pid = get_pgpid();
- if (pid == old_pid)
- {
- write_stderr(_("%s: could not start server\n"
- "Examine the log output.\n"),
- progname);
- exit(1);
- }
- }
-
if (do_wait)
{
print_msg(_("waiting for server to start..."));
/*
- * restart/promote/reload routines
+ * restart/reload routines
*/
static void
}
static void
+do_reload(void)
+{
+ pgpid_t pid;
+
+ pid = get_pgpid();
+ if (pid == 0) /* no pid file */
+ {
+ write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
+ write_stderr(_("Is server running?\n"));
+ exit(1);
+ }
+ else if (pid < 0) /* standalone backend, not postmaster */
+ {
+ pid = -pid;
+ write_stderr(_("%s: cannot reload server; "
+ "single-user server is running (PID: %ld)\n"),
+ progname, pid);
+ write_stderr(_("Please terminate the single-user server and try again.\n"));
+ exit(1);
+ }
+
+ if (kill((pid_t) pid, sig) != 0)
+ {
+ write_stderr(_("%s: could not send reload signal (PID: %ld): %s\n"),
+ progname, pid, strerror(errno));
+ exit(1);
+ }
+
+ print_msg(_("server signaled\n"));
+}
+
+
+/*
+ * promote
+ */
+
+static void
do_promote(void)
{
FILE *prmfile;
}
-static void
-do_reload(void)
-{
- pgpid_t pid;
-
- pid = get_pgpid();
- if (pid == 0) /* no pid file */
- {
- write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
- write_stderr(_("Is server running?\n"));
- exit(1);
- }
- else if (pid < 0) /* standalone backend, not postmaster */
- {
- pid = -pid;
- write_stderr(_("%s: cannot reload server; "
- "single-user server is running (PID: %ld)\n"),
- progname, pid);
- write_stderr(_("Please terminate the single-user server and try again.\n"));
- exit(1);
- }
-
- if (kill((pid_t) pid, sig) != 0)
- {
- write_stderr(_("%s: could not send reload signal (PID: %ld): %s\n"),
- progname, pid, strerror(errno));
- exit(1);
- }
-
- print_msg(_("server signaled\n"));
-}
-
/*
* utility routines
*/
/* concatenate */
sprintf(cmdLine + strlen(cmdLine), " -t %d", wait_seconds);
+ if (registration && silent_mode)
+ strcat(cmdLine, " -s");
+
if (post_opts)
{
strcat(cmdLine, " ");
write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Waiting for server startup...\n"));
if (test_postmaster_connection(true) != PQPING_OK)
{
- write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Timed out waiting for server startup\n"));
+ write_eventlog(EVENTLOG_ERROR_TYPE, _("Timed out waiting for server startup\n"));
pgwin32_SetServiceStatus(SERVICE_STOPPED);
return;
}
* NT4 doesn't have CreateRestrictedToken, so just call ordinary
* CreateProcess
*/
- write_stderr("WARNING: cannot create restricted tokens on this platform\n");
+ write_stderr(_("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
if (Advapi32Handle != NULL)
FreeLibrary(Advapi32Handle);
return CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, processInfo);
/* Open the current token to use as a base for the restricted one */
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
{
- write_stderr("Failed to open process token: %lu\n", GetLastError());
+ write_stderr(_("%s: could not open process token: %lu\n"), progname, GetLastError());
return 0;
}
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
0, &dropSids[1].Sid))
{
- write_stderr("Failed to allocate SIDs: %lu\n", GetLastError());
+ write_stderr(_("%s: could not allocate SIDs: %lu\n"), progname, GetLastError());
return 0;
}
if (!b)
{
- write_stderr("Failed to create restricted token: %lu\n", GetLastError());
+ write_stderr(_("%s: could not create restricted token: %lu\n"), progname, GetLastError());
return 0;
}
* Log error if we can't get version, or if we're on WinXP/2003 or
* newer
*/
- write_stderr("WARNING: could not locate all job object functions in system API\n");
+ write_stderr(_("%s: WARNING: could not locate all job object functions in system API\n"), progname);
}
else
{
static void
do_help(void)
{
- printf(_("%s is a utility to start, stop, restart, promote, reload configuration files,\n"
- "report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
+ printf(_("%s is a utility to initialize, start, stop, or control a PostgreSQL server.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
printf(_(" %s start [-w] [-t SECS] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);
printf(_(" %s stop [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
printf(_(" %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
" [-o \"OPTIONS\"]\n"), progname);
- printf(_(" %s promote [-D DATADIR] [-s]\n"), progname);
printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
printf(_(" %s status [-D DATADIR]\n"), progname);
+ printf(_(" %s promote [-D DATADIR] [-s]\n"), progname);
printf(_(" %s kill SIGNALNAME PID\n"), progname);
#if defined(WIN32) || defined(__CYGWIN__)
printf(_(" %s register [-N SERVICENAME] [-U USERNAME] [-P PASSWORD] [-D DATADIR]\n"
ctl_command = STOP_COMMAND;
else if (strcmp(argv[optind], "restart") == 0)
ctl_command = RESTART_COMMAND;
- else if (strcmp(argv[optind], "promote") == 0)
- ctl_command = PROMOTE_COMMAND;
else if (strcmp(argv[optind], "reload") == 0)
ctl_command = RELOAD_COMMAND;
else if (strcmp(argv[optind], "status") == 0)
ctl_command = STATUS_COMMAND;
+ else if (strcmp(argv[optind], "promote") == 0)
+ ctl_command = PROMOTE_COMMAND;
else if (strcmp(argv[optind], "kill") == 0)
{
if (argc - optind < 3)
case RESTART_COMMAND:
do_restart();
break;
- case PROMOTE_COMMAND:
- do_promote();
- break;
case RELOAD_COMMAND:
do_reload();
break;
+ case PROMOTE_COMMAND:
+ do_promote();
+ break;
case KILL_COMMAND:
do_kill(killproc);
break;