]> granicus.if.org Git - postgresql/blobdiff - src/bin/pg_ctl/pg_ctl.c
Assorted message style improvements
[postgresql] / src / bin / pg_ctl / pg_ctl.c
index e203c1299d03a3272ade1dfd924f59c16ca58906..72fc4c1abf6ae80b92aafea727c9f07d36d9efb3 100644 (file)
@@ -2,7 +2,7 @@
  *
  * 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
  *
@@ -81,6 +81,7 @@ static ShutdownMode shutdown_mode = SMART_MODE;
 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;
@@ -131,6 +132,7 @@ 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 void adjust_data_dir(void);
 
 #if defined(WIN32) || defined(__CYGWIN__)
 static bool pgwin32_IsInstalled(SC_HANDLE);
@@ -163,6 +165,9 @@ write_eventlog(int level, const char *line)
 {
        static HANDLE evtHandle = INVALID_HANDLE_VALUE;
 
+       if (silent_mode && level == EVENTLOG_INFORMATION_TYPE)
+               return;
+
        if (evtHandle == INVALID_HANDLE_VALUE)
        {
                evtHandle = RegisterEventSource(NULL, "PostgreSQL");
@@ -367,9 +372,9 @@ start_postmaster(void)
         * 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,
@@ -476,7 +481,7 @@ test_postmaster_connection(bool do_checkpoint)
                                        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
@@ -489,8 +494,8 @@ test_postmaster_connection(bool do_checkpoint)
                                        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;
                                        }
@@ -549,7 +554,7 @@ test_postmaster_connection(bool do_checkpoint)
                                                 * 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);
                                        }
                                }
@@ -567,11 +572,11 @@ test_postmaster_connection(bool do_checkpoint)
                /*
                 * 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)
                {
@@ -590,7 +595,7 @@ test_postmaster_connection(bool do_checkpoint)
 
                /*
                 * 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.
                 */
@@ -1150,9 +1155,11 @@ do_status(void)
        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))
@@ -1163,7 +1170,7 @@ do_status(void)
                        }
                }
                else
-                       /* postmaster */
+                       /* must be a postmaster */
                {
                        if (postmaster_is_alive((pid_t) pid))
                        {
@@ -1181,7 +1188,14 @@ do_status(void)
                }
        }
        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);
 }
 
 
@@ -1252,7 +1266,7 @@ pgwin32_CommandLine(bool registration)
 
        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");
@@ -1262,10 +1276,10 @@ pgwin32_CommandLine(bool registration)
                strcat(cmdLine, "\"");
        }
 
-       if (pg_data)
+       if (pg_config)
        {
                strcat(cmdLine, " -D \"");
-               strcat(cmdLine, pg_data);
+               strcat(cmdLine, pg_config);
                strcat(cmdLine, "\"");
        }
 
@@ -1276,6 +1290,9 @@ pgwin32_CommandLine(bool registration)
                /* concatenate */
                sprintf(cmdLine + strlen(cmdLine), " -t %d", wait_seconds);
 
+       if (registration && silent_mode)
+               strcat(cmdLine, " -s");
+
        if (post_opts)
        {
                strcat(cmdLine, " ");
@@ -1314,7 +1331,7 @@ pgwin32_doRegister(void)
           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);
@@ -1342,14 +1359,14 @@ pgwin32_doUnregister(void)
        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);
@@ -1400,7 +1417,6 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)
 {
        PROCESS_INFORMATION pi;
        DWORD           ret;
-       DWORD           check_point_start;
 
        /* Initialize variables */
        status.dwWin32ExitCode = S_OK;
@@ -1438,19 +1454,13 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)
                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... */
@@ -1492,7 +1502,7 @@ pgwin32_doRunAsService(void)
 
        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);
        }
 }
@@ -1564,7 +1574,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_ser
                 * 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);
@@ -1573,7 +1583,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_ser
        /* 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;
        }
 
@@ -1586,7 +1596,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_ser
        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;
        }
 
@@ -1605,7 +1615,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_ser
 
        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;
        }
 
@@ -1643,7 +1653,7 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_ser
                         * 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
        {
@@ -1755,13 +1765,13 @@ do_help(void)
 #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"));
 
@@ -1771,12 +1781,12 @@ do_help(void)
 #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"));
@@ -1784,7 +1794,7 @@ do_help(void)
        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"));
@@ -1834,25 +1844,24 @@ set_mode(char *modeopt)
 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
        {
@@ -1880,6 +1889,67 @@ set_starttype(char *starttypeopt)
 }
 #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)
@@ -2114,14 +2184,19 @@ 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"),