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);
* 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)
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) {
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)
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. */