From: Chris Down Date: Wed, 26 Aug 2020 17:49:27 +0000 (+0100) Subject: path: Improve $PATH search directory case X-Git-Tag: v247-rc1~360 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=33e1a5d8d3f792e1d98377fe439e123231032ec7;p=thirdparty%2Fsystemd.git path: Improve $PATH search directory case Previously: 1. last_error wouldn't be updated with errors from is_dir; 2. We'd always issue a stat(), even for binaries without execute; 3. We used stat() instead of access(), which is cheaper. This change avoids all of those, by only checking inside X_OK-positive case whether access() works on the path with an extra slash appended. Thanks to Lennart for the suggestion. --- diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 9fab0e7b5ad..9e44f2e8048 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -638,16 +638,27 @@ int find_binary(const char *name, char **ret) { if (!j) return -ENOMEM; - if (is_dir(j, true)) - continue; - if (access(j, X_OK) >= 0) { - /* Found it! */ + _cleanup_free_ char *with_dash; - if (ret) - *ret = path_simplify(TAKE_PTR(j), false); + with_dash = strjoin(j, "/"); + if (!with_dash) + return -ENOMEM; - return 0; + /* If this passes, it must be a directory, and so should be skipped. */ + if (access(with_dash, X_OK) >= 0) + continue; + + /** + * We can't just `continue` inverting this case, since we need to update last_error. + */ + if (errno == ENOTDIR) { + /* Found it! */ + if (ret) + *ret = path_simplify(TAKE_PTR(j), false); + + return 0; + } } /* PATH entries which we don't have access to are ignored, as per tradition. */