Improve error reporting from validate_exec().
authorTom Lane <[email protected]>
Tue, 12 Jul 2022 19:37:39 +0000 (15:37 -0400)
committerTom Lane <[email protected]>
Tue, 12 Jul 2022 19:37:39 +0000 (15:37 -0400)
validate_exec() didn't guarantee to set errno to something appropriate
after a failure, leading to callers not being able to print an on-point
message.  Improve that.

Noted by Kyotaro Horiguchi, though this isn't exactly his proposal.

Discussion: https://postgr.es/m/20220615.131403.1791191615590453058[email protected]

src/bin/pg_upgrade/exec.c
src/common/exec.c

index 64276223d5086e3bef2b74a92129af10de15c751..aa3d2f88ed840bf4052d37c30800dddc3651ad21 100644 (file)
@@ -423,18 +423,11 @@ check_exec(const char *dir, const char *program, bool check_version)
    char        line[MAXPGPATH];
    char        cmd[MAXPGPATH];
    char        versionstr[128];
-   int         ret;
 
    snprintf(path, sizeof(path), "%s/%s", dir, program);
 
-   ret = validate_exec(path);
-
-   if (ret == -1)
-       pg_fatal("check for \"%s\" failed: does not exist or cannot be executed",
-                path);
-   else if (ret == -2)
-       pg_fatal("check for \"%s\" failed: cannot read (permission denied)",
-                path);
+   if (validate_exec(path) != 0)
+       pg_fatal("check for \"%s\" failed: %m", path);
 
    snprintf(cmd, sizeof(cmd), "\"%s\" -V", path);
 
index 9da588daf9104f0e0f495e7591e4c16c0136b193..f7d44b09569caeb7b2c71088312ea97a117dd8ae 100644 (file)
@@ -74,6 +74,7 @@ static BOOL GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser);
  * returns 0 if the file is found and no error is encountered.
  *       -1 if the regular file "path" does not exist or cannot be executed.
  *       -2 if the file is otherwise valid but cannot be read.
+ * in the failure cases, errno is set appropriately
  */
 int
 validate_exec(const char *path)
@@ -105,7 +106,16 @@ validate_exec(const char *path)
        return -1;
 
    if (!S_ISREG(buf.st_mode))
+   {
+       /*
+        * POSIX offers no errno code that's simply "not a regular file".  If
+        * it's a directory we can use EISDIR.  Otherwise, it's most likely a
+        * device special file, and EPERM (Operation not permitted) isn't too
+        * horribly off base.
+        */
+       errno = S_ISDIR(buf.st_mode) ? EISDIR : EPERM;
        return -1;
+   }
 
    /*
     * Ensure that the file is both executable and readable (required for
@@ -114,9 +124,11 @@ validate_exec(const char *path)
 #ifndef WIN32
    is_r = (access(path, R_OK) == 0);
    is_x = (access(path, X_OK) == 0);
+   /* access() will set errno if it returns -1 */
 #else
    is_r = buf.st_mode & S_IRUSR;
    is_x = buf.st_mode & S_IXUSR;
+   errno = EACCES;             /* appropriate thing if we return nonzero */
 #endif
    return is_x ? (is_r ? 0 : -2) : -1;
 }
@@ -165,7 +177,7 @@ find_my_exec(const char *argv0, char *retpath)
            return resolve_symlinks(retpath);
 
        log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                 _("invalid binary \"%s\""), retpath);
+                 _("invalid binary \"%s\": %m"), retpath);
        return -1;
    }
 
@@ -215,7 +227,7 @@ find_my_exec(const char *argv0, char *retpath)
                    break;
                case -2:        /* found but disqualified */
                    log_error(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                             _("could not read binary \"%s\""),
+                             _("could not read binary \"%s\": %m"),
                              retpath);
                    break;
            }