From: Mike Yuan Date: Sat, 5 Apr 2025 20:29:33 +0000 (+0200) Subject: path-util: generalize open_and_check_executable() X-Git-Tag: v258-rc1~902^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=326d60a9d0605f02936d0aa8ec5cf78cae72f5dd;p=thirdparty%2Fsystemd.git path-util: generalize open_and_check_executable() --- diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 78ba10ed809..dbde364effd 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -613,37 +613,9 @@ char* path_extend_internal(char **x, ...) { return nx; } -static int check_x_access(const char *path, int *ret_fd) { +int open_and_check_executable(const char *name, const char *root, char **ret_path, int *ret_fd) { _cleanup_close_ int fd = -EBADF; - int r; - - /* We need to use O_PATH because there may be executables for which we have only exec - * permissions, but not read (usually suid executables). */ - fd = open(path, O_PATH|O_CLOEXEC); - if (fd < 0) - return -errno; - - r = fd_verify_regular(fd); - if (r < 0) - return r; - - r = access_fd(fd, X_OK); - if (r == -ENOSYS) { - /* /proc is not mounted. Fallback to access(). */ - if (access(path, X_OK) < 0) - return -errno; - } else if (r < 0) - return r; - - if (ret_fd) - *ret_fd = TAKE_FD(fd); - - return 0; -} - -static int find_executable_impl(const char *name, const char *root, char **ret_filename, int *ret_fd) { - _cleanup_close_ int fd = -EBADF; - _cleanup_free_ char *path_name = NULL; + _cleanup_free_ char *resolved = NULL; int r; assert(name); @@ -654,23 +626,40 @@ static int find_executable_impl(const char *name, const char *root, char **ret_f * needed to avoid unforeseen regression or other complicated changes. */ if (root) { /* prefix root to name in case full paths are not specified */ - r = chase(name, root, CHASE_PREFIX_ROOT, &path_name, /* ret_fd= */ NULL); + r = chase(name, root, CHASE_PREFIX_ROOT, &resolved, &fd); if (r < 0) return r; - name = path_name; + name = resolved; + } else { + /* We need to use O_PATH because there may be executables for which we have only exec permissions, + * but not read (usually suid executables). */ + fd = open(name, O_PATH|O_CLOEXEC); + if (fd < 0) + return -errno; } - r = check_x_access(name, ret_fd ? &fd : NULL); + r = fd_verify_regular(fd); if (r < 0) return r; - if (ret_filename) { - r = path_make_absolute_cwd(name, ret_filename); - if (r < 0) - return r; + r = access_fd(fd, X_OK); + if (r == -ENOSYS) + /* /proc/ is not mounted. Fall back to access(). */ + r = RET_NERRNO(access(name, X_OK)); + if (r < 0) + return r; - path_simplify(*ret_filename); + if (ret_path) { + if (resolved) + *ret_path = TAKE_PTR(resolved); + else { + r = path_make_absolute_cwd(name, ret_path); + if (r < 0) + return r; + + path_simplify(*ret_path); + } } if (ret_fd) @@ -692,7 +681,7 @@ int find_executable_full( assert(name); if (is_path(name)) - return find_executable_impl(name, root, ret_filename, ret_fd); + return open_and_check_executable(name, root, ret_filename, ret_fd); if (exec_search_path) { STRV_FOREACH(element, exec_search_path) { @@ -707,7 +696,7 @@ int find_executable_full( if (!full_path) return -ENOMEM; - r = find_executable_impl(full_path, root, ret_filename, ret_fd); + r = open_and_check_executable(full_path, root, ret_filename, ret_fd); if (r >= 0) return 0; if (r != -EACCES) @@ -743,7 +732,7 @@ int find_executable_full( if (!path_extend(&element, name)) return -ENOMEM; - r = find_executable_impl(element, root, ret_filename, ret_fd); + r = open_and_check_executable(element, root, ret_filename, ret_fd); if (r >= 0) /* Found it! */ return 0; /* PATH entries which we don't have access to are ignored, as per tradition. */ diff --git a/src/basic/path-util.h b/src/basic/path-util.h index dff5a3a549c..436bd5d8927 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -115,6 +115,7 @@ int path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *root); char** path_strv_resolve_uniq(char **l, const char *root); +int open_and_check_executable(const char *name, const char *root, char **ret_path, int *ret_fd); int find_executable_full( const char *name, const char *root,