*
* pg_ctl --- start/stops/restarts the PostgreSQL server
*
- * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
*
* src/bin/pg_ctl/pg_ctl.c
*
static int sig = SIGTERM; /* default */
static CtlCommand ctl_command = NO_COMMAND;
static char *pg_data = NULL;
+static char *pg_config = NULL;
static char *pgdata_opt = NULL;
static char *post_opts = NULL;
static const char *progname;
static void do_promote(void);
static void do_kill(pgpid_t pid);
static void print_msg(const char *msg);
+static void adjust_data_dir(void);
#if defined(WIN32) || defined(__CYGWIN__)
static bool pgwin32_IsInstalled(SC_HANDLE);
{
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.
+ * 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,
time_t pmstart;
/*
- * Make sanity checks. If it's for a standalone backend
+ * 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
if (pmpid <= 0 || pmstart < start_time - 2)
{
/*
- * Set flag to report stale pidfile if it doesn't
- * get overwritten before we give up waiting.
+ * Set flag to report stale pidfile if it doesn't get
+ * overwritten before we give up waiting.
*/
found_stale_pidfile = true;
}
* timeout first.
*/
snprintf(connstr, sizeof(connstr),
- "dbname=postgres port=%d host='%s' connect_timeout=5",
+ "dbname=postgres port=%d host='%s' connect_timeout=5",
portnum, host_str);
}
}
/*
* 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.
+ * 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)
{
/*
* If we've been able to identify the child postmaster's PID, check
- * the process is still alive. This covers cases where the postmaster
+ * the process is still alive. This covers cases where the postmaster
* successfully created the pidfile but then crashed without removing
* it.
*/
pgpid_t pid;
pid = get_pgpid();
- if (pid != 0) /* 0 means no pid file */
+ /* Is there a pid file? */
+ if (pid != 0)
{
- if (pid < 0) /* standalone backend */
+ /* standalone backend? */
+ if (pid < 0)
{
pid = -pid;
if (postmaster_is_alive((pid_t) pid))
}
}
else
- /* postmaster */
+ /* must be a postmaster */
{
if (postmaster_is_alive((pid_t) pid))
{
}
}
printf(_("%s: no server running\n"), progname);
- exit(1);
+
+ /*
+ * The Linux Standard Base Core Specification 3.1 says this should return
+ * '3'
+ * http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-ge
+ * neric/iniscrptact.html
+ */
+ exit(3);
}
if (registration)
{
- if (pg_strcasecmp(cmdLine + strlen(cmdLine) - 4, ".exe"))
+ if (pg_strcasecmp(cmdLine + strlen(cmdLine) - 4, ".exe") != 0)
{
/* If commandline does not end in .exe, append it */
strcat(cmdLine, ".exe");
strcat(cmdLine, "\"");
}
- if (pg_data)
+ if (pg_config)
{
strcat(cmdLine, " -D \"");
- strcat(cmdLine, pg_data);
+ strcat(cmdLine, pg_config);
strcat(cmdLine, "\"");
}
/* concatenate */
sprintf(cmdLine + strlen(cmdLine), " -t %d", wait_seconds);
+ if (registration && silent_mode)
+ strcat(cmdLine, " -s");
+
if (post_opts)
{
strcat(cmdLine, " ");
NULL, NULL, "RPCSS\0", register_username, register_password)) == NULL)
{
CloseServiceHandle(hSCM);
- write_stderr(_("%s: could not register service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());
+ write_stderr(_("%s: could not register service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
exit(1);
}
CloseServiceHandle(hService);
if ((hService = OpenService(hSCM, register_servicename, DELETE)) == NULL)
{
CloseServiceHandle(hSCM);
- write_stderr(_("%s: could not open service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());
+ write_stderr(_("%s: could not open service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
exit(1);
}
if (!DeleteService(hService))
{
CloseServiceHandle(hService);
CloseServiceHandle(hSCM);
- write_stderr(_("%s: could not unregister service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());
+ write_stderr(_("%s: could not unregister service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
exit(1);
}
CloseServiceHandle(hService);
{
PROCESS_INFORMATION pi;
DWORD ret;
- DWORD check_point_start;
/* Initialize variables */
status.dwWin32ExitCode = S_OK;
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;
}
write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Server started and accepting connections\n"));
}
- /*
- * Save the checkpoint value as it might have been incremented in
- * test_postmaster_connection
- */
- check_point_start = status.dwCheckPoint;
-
pgwin32_SetServiceStatus(SERVICE_RUNNING);
/* Wait for quit... */
if (StartServiceCtrlDispatcher(st) == 0)
{
- write_stderr(_("%s: could not start service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());
+ write_stderr(_("%s: could not start service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
exit(1);
}
}
* 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: error code %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: error code %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: error code %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
{
#endif
printf(_("\nCommon options:\n"));
- printf(_(" -D, --pgdata DATADIR location of the database storage area\n"));
+ printf(_(" -D, --pgdata=DATADIR location of the database storage area\n"));
printf(_(" -s, --silent only print errors, no informational messages\n"));
- printf(_(" -t SECS seconds to wait when using -w option\n"));
+ printf(_(" -t, --timeout=SECS seconds to wait when using -w option\n"));
+ printf(_(" -V, --version output version information, then exit\n"));
printf(_(" -w wait until operation completes\n"));
printf(_(" -W do not wait until operation completes\n"));
- printf(_(" --help show this help, then exit\n"));
- printf(_(" --version output version information, then exit\n"));
+ printf(_(" -?, --help show this help, then exit\n"));
printf(_("(The default is to wait for shutdown, but not for start or restart.)\n\n"));
printf(_("If the -D option is omitted, the environment variable PGDATA is used.\n"));
#else
printf(_(" -c, --core-files not applicable on this platform\n"));
#endif
- printf(_(" -l, --log FILENAME write (or append) server log to FILENAME\n"));
+ printf(_(" -l, --log=FILENAME write (or append) server log to FILENAME\n"));
printf(_(" -o OPTIONS command line options to pass to postgres\n"
" (PostgreSQL server executable) or initdb\n"));
printf(_(" -p PATH-TO-POSTGRES normally not necessary\n"));
printf(_("\nOptions for stop or restart:\n"));
- printf(_(" -m SHUTDOWN-MODE can be \"smart\", \"fast\", or \"immediate\"\n"));
+ printf(_(" -m, --mode=MODE MODE can be \"smart\", \"fast\", or \"immediate\"\n"));
printf(_("\nShutdown modes are:\n"));
printf(_(" smart quit after all clients have disconnected\n"));
printf(_(" immediate quit without complete shutdown; will lead to recovery on restart\n"));
printf(_("\nAllowed signal names for kill:\n"));
- printf(" HUP INT QUIT ABRT TERM USR1 USR2\n");
+ printf(" ABRT HUP INT QUIT TERM USR1 USR2\n");
#if defined(WIN32) || defined(__CYGWIN__)
printf(_("\nOptions for register and unregister:\n"));
static void
set_sig(char *signame)
{
- if (!strcmp(signame, "HUP"))
+ if (strcmp(signame, "HUP") == 0)
sig = SIGHUP;
- else if (!strcmp(signame, "INT"))
+ else if (strcmp(signame, "INT") == 0)
sig = SIGINT;
- else if (!strcmp(signame, "QUIT"))
+ else if (strcmp(signame, "QUIT") == 0)
sig = SIGQUIT;
- else if (!strcmp(signame, "ABRT"))
+ else if (strcmp(signame, "ABRT") == 0)
sig = SIGABRT;
-
- /*
- * probably should NOT provide SIGKILL
- *
- * else if (!strcmp(signame,"KILL")) sig = SIGKILL;
- */
- else if (!strcmp(signame, "TERM"))
+#if 0
+ /* probably should NOT provide SIGKILL */
+ else if (strcmp(signame, "KILL") == 0)
+ sig = SIGKILL;
+#endif
+ else if (strcmp(signame, "TERM") == 0)
sig = SIGTERM;
- else if (!strcmp(signame, "USR1"))
+ else if (strcmp(signame, "USR1") == 0)
sig = SIGUSR1;
- else if (!strcmp(signame, "USR2"))
+ else if (strcmp(signame, "USR2") == 0)
sig = SIGUSR2;
else
{
}
#endif
+/*
+ * adjust_data_dir
+ *
+ * If a configuration-only directory was specified, find the real data dir.
+ */
+static void
+adjust_data_dir(void)
+{
+ char cmd[MAXPGPATH],
+ filename[MAXPGPATH],
+ *my_exec_path;
+ FILE *fd;
+
+ /* do nothing if we're working without knowledge of data dir */
+ if (pg_config == NULL)
+ return;
+
+ /* If there is no postgresql.conf, it can't be a config-only dir */
+ snprintf(filename, sizeof(filename), "%s/postgresql.conf", pg_config);
+ if ((fd = fopen(filename, "r")) == NULL)
+ return;
+ fclose(fd);
+
+ /* If PG_VERSION exists, it can't be a config-only dir */
+ snprintf(filename, sizeof(filename), "%s/PG_VERSION", pg_config);
+ if ((fd = fopen(filename, "r")) != NULL)
+ {
+ fclose(fd);
+ return;
+ }
+
+ /* Must be a configuration directory, so find the data directory */
+
+ /* we use a private my_exec_path to avoid interfering with later uses */
+ if (exec_path == NULL)
+ my_exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
+ else
+ my_exec_path = xstrdup(exec_path);
+
+ snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s -C data_directory" SYSTEMQUOTE,
+ my_exec_path, pgdata_opt ? pgdata_opt : "", post_opts ?
+ post_opts : "");
+
+ fd = popen(cmd, "r");
+ if (fd == NULL || fgets(filename, sizeof(filename), fd) == NULL)
+ {
+ write_stderr(_("%s: could not determine the data directory using command \"%s\"\n"), progname, cmd);
+ exit(1);
+ }
+ pclose(fd);
+ free(my_exec_path);
+
+ /* Remove trailing newline */
+ if (strchr(filename, '\n') != NULL)
+ *strchr(filename, '\n') = '\0';
+
+ free(pg_data);
+ pg_data = xstrdup(filename);
+ canonicalize_path(pg_data);
+}
+
int
main(int argc, char **argv)
}
/* Note we put any -D switch into the env var above */
- pg_data = getenv("PGDATA");
- if (pg_data)
+ pg_config = getenv("PGDATA");
+ if (pg_config)
{
- pg_data = xstrdup(pg_data);
- canonicalize_path(pg_data);
+ pg_config = xstrdup(pg_config);
+ canonicalize_path(pg_config);
+ pg_data = xstrdup(pg_config);
}
- if (pg_data == NULL &&
+ /* -D might point at config-only directory; if so find the real PGDATA */
+ adjust_data_dir();
+
+ /* Complain if -D needed and not provided */
+ if (pg_config == NULL &&
ctl_command != KILL_COMMAND && ctl_command != UNREGISTER_COMMAND)
{
write_stderr(_("%s: no database directory specified and environment variable PGDATA unset\n"),