pg_ctl: improve handling of invalid data directory
authorBruce Momjian
Sat, 8 Mar 2014 17:15:25 +0000 (12:15 -0500)
committerBruce Momjian
Sat, 8 Mar 2014 17:15:25 +0000 (12:15 -0500)
Return '4' and report a meaningful error message when a non-existent or
invalid data directory is passed.  Previously, pg_ctl would just report
the server was not running.

Patch by me and Amit Kapila
Report from Peter Eisentraut

doc/src/sgml/ref/pg_ctl-ref.sgml
src/bin/pg_ctl/pg_ctl.c

index 45b53ce1a1a6920641a7b1b34f0c908546d429b6..52bcf5e81538ee8085febae0c9f615a7ce3a9248 100644 (file)
@@ -208,7 +208,8 @@ PostgreSQL documentation
    the specified data directory. If it is, the PID
    and the command line options that were used to invoke it are
    displayed.  If the server is not running, the process returns an
-   exit status of 3.
+   exit status of 3.  If an accessible data directory is not specified,
+   the process returns an exit status of 4.
   
 
   
index 0dbaa6e27fe5009d7f0e95710309bc7056779c61..56d238f39481da3c8bd5043e8889a3e58cfdca84 100644 (file)
@@ -97,6 +97,7 @@ static bool allow_core_files = false;
 static time_t start_time;
 
 static char postopts_file[MAXPGPATH];
+static char version_file[MAXPGPATH];
 static char pid_file[MAXPGPATH];
 static char backup_file[MAXPGPATH];
 static char recovery_file[MAXPGPATH];
@@ -152,7 +153,7 @@ static void pgwin32_doRunAsService(void);
 static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service);
 #endif
 
-static pgpid_t get_pgpid(void);
+static pgpid_t get_pgpid(bool is_status_request);
 static char **readfile(const char *path);
 static void free_readfile(char **optlines);
 static int start_postmaster(void);
@@ -246,10 +247,34 @@ print_msg(const char *msg)
 }
 
 static pgpid_t
-get_pgpid(void)
+get_pgpid(bool is_status_request)
 {
    FILE       *pidf;
    long        pid;
+   struct stat statbuf;
+
+   if (stat(pg_data, &statbuf) != 0)
+   {
+       if (errno == ENOENT)
+           printf(_("%s: directory \"%s\" does not exist\n"), progname,
+                    pg_data);
+       else
+           printf(_("%s: cannot access directory \"%s\"\n"), progname,
+                    pg_data);
+       /*
+        * The Linux Standard Base Core Specification 3.1 says this should return
+        * '4, program or service status is unknown'
+        * https://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
+        */
+       exit(is_status_request ? 4 : 1);
+   }
+
+   if (stat(version_file, &statbuf) != 0 && errno == ENOENT)
+   {
+       printf(_("%s: directory \"%s\" is not a database cluster directory\n"),
+                progname, pg_data);
+       exit(is_status_request ? 4 : 1);
+   }
 
    pidf = fopen(pid_file, "r");
    if (pidf == NULL)
@@ -810,7 +835,7 @@ do_start(void)
 
    if (ctl_command != RESTART_COMMAND)
    {
-       old_pid = get_pgpid();
+       old_pid = get_pgpid(false);
        if (old_pid != 0)
            write_stderr(_("%s: another server might be running; "
                           "trying to start server anyway\n"),
@@ -894,7 +919,7 @@ do_stop(void)
    pgpid_t     pid;
    struct stat statbuf;
 
-   pid = get_pgpid();
+   pid = get_pgpid(false);
 
    if (pid == 0)               /* no pid file */
    {
@@ -943,7 +968,7 @@ do_stop(void)
 
        for (cnt = 0; cnt < wait_seconds; cnt++)
        {
-           if ((pid = get_pgpid()) != 0)
+           if ((pid = get_pgpid(false)) != 0)
            {
                print_msg(".");
                pg_usleep(1000000);     /* 1 sec */
@@ -980,7 +1005,7 @@ do_restart(void)
    pgpid_t     pid;
    struct stat statbuf;
 
-   pid = get_pgpid();
+   pid = get_pgpid(false);
 
    if (pid == 0)               /* no pid file */
    {
@@ -1033,7 +1058,7 @@ do_restart(void)
 
        for (cnt = 0; cnt < wait_seconds; cnt++)
        {
-           if ((pid = get_pgpid()) != 0)
+           if ((pid = get_pgpid(false)) != 0)
            {
                print_msg(".");
                pg_usleep(1000000);     /* 1 sec */
@@ -1071,7 +1096,7 @@ do_reload(void)
 {
    pgpid_t     pid;
 
-   pid = get_pgpid();
+   pid = get_pgpid(false);
    if (pid == 0)               /* no pid file */
    {
        write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
@@ -1110,7 +1135,7 @@ do_promote(void)
    pgpid_t     pid;
    struct stat statbuf;
 
-   pid = get_pgpid();
+   pid = get_pgpid(false);
 
    if (pid == 0)               /* no pid file */
    {
@@ -1204,7 +1229,7 @@ do_status(void)
 {
    pgpid_t     pid;
 
-   pid = get_pgpid();
+   pid = get_pgpid(true);
    /* Is there a pid file? */
    if (pid != 0)
    {
@@ -1247,7 +1272,7 @@ do_status(void)
 
    /*
     * The Linux Standard Base Core Specification 3.1 says this should return
-    * '3'
+    * '3, program is not running'
     * https://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
     */
    exit(3);
@@ -2285,6 +2310,7 @@ main(int argc, char **argv)
    if (pg_data)
    {
        snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
+       snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", pg_data);
        snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
        snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
        snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);