When the root parameter in find_executable_full is set, chase_symlinks prefixes this root
to every check of the path name to find the complete path of the execuatble in case the
path provided is not absolute. This is only done for the non NULL root because otherwise
the chase_symlinks function would alter the behavior of some of the callers which would
in turn alter the outputs in a way that is undesirable. The find_execuatble_full function is
invoked by the verify_executable function in analyze-verify.
if (exec->flags & EXEC_COMMAND_IGNORE_FAILURE)
return 0;
- r = find_executable_full(exec->path, false, NULL, NULL);
+ r = find_executable_full(exec->path, /* root= */ NULL, false, NULL, NULL);
if (r < 0)
return log_unit_error_errno(u, r, "Command %s is not executable: %m", exec->path);
return 0;
}
-int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd) {
+int find_executable_full(const char *name, const char *root, bool use_path_envvar, char **ret_filename, int *ret_fd) {
int last_error, r;
const char *p = NULL;
if (is_path(name)) {
_cleanup_close_ int fd = -1;
+ _cleanup_free_ char *path_name = NULL;
+
+ /* Function chase_symlinks() is invoked only when root is not NULL,
+ * as using it regardless of root value would alter the behavior
+ * of existing callers for example: /bin/sleep would become
+ * /usr/bin/sleep when find_executables is called. Hence, this function
+ * should be invoked when needed to avoid unforeseen regression or other
+ * complicated changes. */
+ if (root) {
+ r = chase_symlinks(name,
+ root,
+ CHASE_PREFIX_ROOT,
+ &path_name,
+ /* ret_fd= */ NULL); /* prefix root to name in case full paths are not specified */
+ if (r < 0)
+ return r;
+
+ name = path_name;
+ }
r = check_x_access(name, ret_fd ? &fd : NULL);
if (r < 0)
if (!path_extend(&element, name))
return -ENOMEM;
+ if (root) {
+ char *path_name;
+
+ r = chase_symlinks(element,
+ root,
+ CHASE_PREFIX_ROOT,
+ &path_name,
+ /* ret_fd= */ NULL);
+ if (r < 0) {
+ if (r != -EACCES)
+ last_error = r;
+ continue;
+ }
+
+ free_and_replace(element, path_name);
+ }
+
r = check_x_access(element, ret_fd ? &fd : NULL);
if (r < 0) {
/* PATH entries which we don't have access to are ignored, as per tradition. */
char** path_strv_resolve(char **l, const char *root);
char** path_strv_resolve_uniq(char **l, const char *root);
-int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd);
+int find_executable_full(const char *name, const char *root, bool use_path_envvar, char **ret_filename, int *ret_fd);
static inline int find_executable(const char *name, char **ret_filename) {
- return find_executable_full(name, true, ret_filename, NULL);
+ return find_executable_full(name, /* root= */ NULL, true, ret_filename, NULL);
}
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
_cleanup_free_ char *executable = NULL;
_cleanup_close_ int executable_fd = -1;
- r = find_executable_full(command->path, false, &executable, &executable_fd);
+ r = find_executable_full(command->path, /* root= */ NULL, false, &executable, &executable_fd);
if (r < 0) {
if (r != -ENOMEM && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
log_unit_struct_errno(unit, LOG_INFO, r,
log_info("/* %s */", __func__);
- assert_se(find_executable_full("sh", true, &p, NULL) == 0);
+ assert_se(find_executable_full("sh", NULL, true, &p, NULL) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
- assert_se(find_executable_full("sh", false, &p, NULL) == 0);
+ assert_se(find_executable_full("sh", NULL, false, &p, NULL) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
assert_se(unsetenv("PATH") == 0);
- assert_se(find_executable_full("sh", true, &p, NULL) == 0);
+ assert_se(find_executable_full("sh", NULL, true, &p, NULL) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
- assert_se(find_executable_full("sh", false, &p, NULL) == 0);
+ assert_se(find_executable_full("sh", NULL, false, &p, NULL) == 0);
puts(p);
assert_se(streq(basename(p), "sh"));
free(p);
pid_t pid;
int r;
- r = find_executable_full(path, false, &t, &fd);
+ r = find_executable_full(path, NULL, false, &t, &fd);
log_info_errno(r, "%s: %s → %s: %d/%m", __func__, path, t ?: "-", fd);