1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-20 14:03:39 +03:00

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.

(cherry picked from commit 33e1a5d8d3f792e1d98377fe439e123231032ec7)
(cherry picked from commit a4236a27644705e58836f5d547d5aef50d568c11)
(cherry picked from commit 6a30d4e98032575d385a09d15782be74cbef6dfe)
(cherry picked from commit 0783b4f8cecda4f21e9021495377e2c807a32a5e)
This commit is contained in:
Chris Down 2020-08-26 18:49:27 +01:00 committed by Zbigniew Jędrzejewski-Szmek
parent 67d1efbc89
commit 78a267e2e3

View File

@ -640,19 +640,28 @@ int find_binary(const char *name, char **ret) {
if (!j)
return -ENOMEM;
if (is_dir(j, true))
if (access(j, X_OK) >= 0) {
_cleanup_free_ char *with_dash;
with_dash = strjoin(j, "/");
if (!with_dash)
return -ENOMEM;
/* If this passes, it must be a directory, and so should be skipped. */
if (access(with_dash, X_OK) >= 0)
continue;
if (access(j, X_OK) >= 0) {
/**
* 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(j, false);
j = NULL;
}
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. */
if (errno != EACCES)