basic/fs-util: change CHASE_OPEN flag into a separate output parameter

chase_symlinks() would return negative on error, and either a non-negative status
or a non-negative fd when CHASE_OPEN was given. This made the interface quite
complicated, because dependning on the flags used, we would get two different
"types" of return object. Coverity was always confused by this, and flagged
every use of chase_symlinks() without CHASE_OPEN as a resource leak (because it
would this that an fd is returned). This patch uses a saparate output parameter,
so there is no confusion.

(I think it is OK to have functions which return either an error or an fd. It's
only returning *either* an fd or a non-fd that is confusing.)
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-10-24 10:33:20 +02:00 committed by Yu Watanabe
parent 58ce85f6a1
commit a5648b8094
33 changed files with 197 additions and 180 deletions

View File

@ -713,7 +713,7 @@ static int log_autofs_mount_point(int fd, const char *path, unsigned flags) {
n1, path);
}
int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) {
int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) {
_cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
_cleanup_close_ int fd = -1;
unsigned max_follow = CHASE_SYMLINKS_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
@ -725,10 +725,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
assert(path);
/* Either the file may be missing, or we return an fd to the final object, but both make no sense */
if (FLAGS_SET(flags, CHASE_NONEXISTENT | CHASE_OPEN))
if ((flags & CHASE_NONEXISTENT) && ret_fd)
return -EINVAL;
if (FLAGS_SET(flags, CHASE_STEP | CHASE_OPEN))
if ((flags & CHASE_STEP) && ret_fd)
return -EINVAL;
if (isempty(path))
@ -754,17 +754,17 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
* function what to do when encountering a symlink with an absolute path as directory: prefix it by the
* specified path.
*
* There are three ways to invoke this function:
* There are five ways to invoke this function:
*
* 1. Without CHASE_STEP or CHASE_OPEN: in this case the path is resolved and the normalized path is returned
* in `ret`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0 is returned if the file
* doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is returned if the destination was
* found, -ENOENT if it wasn't.
* 1. Without CHASE_STEP or ret_fd: in this case the path is resolved and the normalized path is
* returned in `ret_path`. The return value is < 0 on error. If CHASE_NONEXISTENT is also set, 0
* is returned if the file doesn't exist, > 0 otherwise. If CHASE_NONEXISTENT is not set, >= 0 is
* returned if the destination was found, -ENOENT if it wasn't.
*
* 2. With CHASE_OPEN: in this case the destination is opened after chasing it as O_PATH and this file
* 2. With ret_fd: in this case the destination is opened after chasing it as O_PATH and this file
* descriptor is returned as return value. This is useful to open files relative to some root
* directory. Note that the returned O_PATH file descriptors must be converted into a regular one (using
* fd_reopen() or such) before it can be used for reading/writing. CHASE_OPEN may not be combined with
* fd_reopen() or such) before it can be used for reading/writing. ret_fd may not be combined with
* CHASE_NONEXISTENT.
*
* 3. With CHASE_STEP: in this case only a single step of the normalization is executed, i.e. only the first
@ -780,21 +780,21 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
* 5. With CHASE_NO_AUTOFS: in this case if an autofs mount point is encountered, path normalization
* is aborted and -EREMOTE is returned. If CHASE_WARN is also set, a warning showing the path of
* the mount point is emitted.
*
*/
/* A root directory of "/" or "" is identical to none */
if (empty_or_root(original_root))
original_root = NULL;
if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN|CHASE_STEP)) == CHASE_OPEN) {
/* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set
if (!original_root && !ret_path && !(flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP)) && ret_fd) {
/* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root set
* and doesn't care about any of the other special features we provide either. */
r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
if (r < 0)
return -errno;
return r;
*ret_fd = r;
return 0;
}
if (original_root) {
@ -803,7 +803,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
return r;
if (flags & CHASE_PREFIX_ROOT) {
/* We don't support relative paths in combination with a root directory */
if (!path_is_absolute(path))
return -EINVAL;
@ -948,7 +947,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
char *joined;
_cleanup_free_ char *destination = NULL;
/* This is a symlink, in this case read the destination. But let's make sure we don't follow
@ -1034,15 +1032,15 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
return -ENOMEM;
}
if (ret)
*ret = TAKE_PTR(done);
if (ret_path)
*ret_path = TAKE_PTR(done);
if (flags & CHASE_OPEN) {
/* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by
* opening /proc/self/fd/xyz. */
if (ret_fd) {
/* Return the O_PATH fd we currently are looking to the caller. It can translate it to a
* proper fd by opening /proc/self/fd/xyz. */
assert(fd >= 0);
return TAKE_FD(fd);
*ret_fd = TAKE_FD(fd);
}
if (flags & CHASE_STEP)
@ -1051,14 +1049,14 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
return exists;
chased_one:
if (ret) {
if (ret_path) {
char *c;
c = strjoin(strempty(done), todo);
if (!c)
return -ENOMEM;
*ret = c;
*ret_path = c;
}
return 0;
@ -1087,9 +1085,10 @@ int chase_symlinks_and_open(
return r;
}
path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
if (path_fd < 0)
return path_fd;
r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
if (r < 0)
return r;
assert(path_fd >= 0);
r = fd_reopen(path_fd, open_flags);
if (r < 0)
@ -1112,6 +1111,7 @@ int chase_symlinks_and_opendir(
_cleanup_close_ int path_fd = -1;
_cleanup_free_ char *p = NULL;
DIR *d;
int r;
if (!ret_dir)
return -EINVAL;
@ -1128,9 +1128,10 @@ int chase_symlinks_and_opendir(
return 0;
}
path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
if (path_fd < 0)
return path_fd;
r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
if (r < 0)
return r;
assert(path_fd >= 0);
xsprintf(procfs_path, "/proc/self/fd/%i", path_fd);
d = opendir(procfs_path);
@ -1149,10 +1150,12 @@ int chase_symlinks_and_stat(
const char *root,
unsigned chase_flags,
char **ret_path,
struct stat *ret_stat) {
struct stat *ret_stat,
int *ret_fd) {
_cleanup_close_ int path_fd = -1;
_cleanup_free_ char *p = NULL;
int r;
assert(path);
assert(ret_stat);
@ -1168,18 +1171,18 @@ int chase_symlinks_and_stat(
return 1;
}
path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
if (path_fd < 0)
return path_fd;
r = chase_symlinks(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
if (r < 0)
return r;
assert(path_fd >= 0);
if (fstat(path_fd, ret_stat) < 0)
return -errno;
if (ret_path)
*ret_path = TAKE_PTR(p);
if (chase_flags & CHASE_OPEN)
return TAKE_FD(path_fd);
if (ret_fd)
*ret_fd = TAKE_FD(path_fd);
return 1;
}

View File

@ -79,23 +79,21 @@ enum {
CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
CHASE_NO_AUTOFS = 1 << 2, /* Return -EREMOTE if autofs mount point found */
CHASE_SAFE = 1 << 3, /* Return EPERM if we ever traverse from unprivileged to privileged files or directories */
CHASE_OPEN = 1 << 4, /* Return an O_PATH object to the final component */
CHASE_TRAIL_SLASH = 1 << 5, /* Any trailing slash will be preserved */
CHASE_STEP = 1 << 6, /* Just execute a single step of the normalization */
CHASE_NOFOLLOW = 1 << 7, /* Do not follow the path's right-most compontent. With CHASE_OPEN, when
* the path's right-most component refers to symlink, return O_PATH fd of
* the symlink. */
CHASE_WARN = 1 << 8, /* Emit an appropriate warning when an error is encountered */
CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */
CHASE_STEP = 1 << 5, /* Just execute a single step of the normalization */
CHASE_NOFOLLOW = 1 << 6, /* Do not follow the path's right-most compontent. With ret_fd, when the path's
* right-most component refers to symlink, return O_PATH fd of the symlink. */
CHASE_WARN = 1 << 7, /* Emit an appropriate warning when an error is encountered */
};
/* How many iterations to execute before returning -ELOOP */
#define CHASE_SYMLINKS_MAX 32
int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret);
int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret_path, int *ret_fd);
int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path);
int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir);
int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat);
int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd);
/* Useful for usage with _cleanup_(), removes a directory and frees the pointer */
static inline void rmdir_and_free(char *p) {

View File

@ -33,7 +33,7 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, Mkd
if ((flags & MKDIR_FOLLOW_SYMLINK) && S_ISLNK(st.st_mode)) {
_cleanup_free_ char *p = NULL;
r = chase_symlinks(path, NULL, CHASE_NONEXISTENT, &p);
r = chase_symlinks(path, NULL, CHASE_NONEXISTENT, &p, NULL);
if (r < 0)
return r;
if (r == 0)

View File

@ -264,7 +264,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
* /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
* look at needs to be /usr, not /. */
if (flags & AT_SYMLINK_FOLLOW) {
r = chase_symlinks(t, root, CHASE_TRAIL_SLASH, &canonical);
r = chase_symlinks(t, root, CHASE_TRAIL_SLASH, &canonical, NULL);
if (r < 0)
return r;

View File

@ -273,7 +273,7 @@ char **path_strv_resolve(char **l, const char *root) {
} else
t = *s;
r = chase_symlinks(t, root, 0, &u);
r = chase_symlinks(t, root, 0, &u, NULL);
if (r == -ENOENT) {
if (root) {
u = TAKE_PTR(orig);

View File

@ -335,7 +335,7 @@ int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) {
if (r < 0)
return r;
return chase_symlinks(p, NULL, 0, ret);
return chase_symlinks(p, NULL, 0, ret, NULL);
}
int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) {

View File

@ -1471,7 +1471,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
if (!path_is_absolute(init))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path to init binary '%s' not absolute.", init);
r = chase_symlinks(init, root, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &chased);
r = chase_symlinks(init, root, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &chased, NULL);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Could not resolve init executable %s: %m", init);

View File

@ -875,7 +875,7 @@ static int follow_symlink(
* a time by specifying CHASE_STEP. This function returns 0 if we resolved one step, and > 0 if we reached the
* end and already have a fully normalized name. */
r = chase_symlinks(mount_entry_path(m), root_directory, CHASE_STEP|CHASE_NONEXISTENT, &target);
r = chase_symlinks(mount_entry_path(m), root_directory, CHASE_STEP|CHASE_NONEXISTENT, &target, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to chase symlinks '%s': %m", mount_entry_path(m));
if (r > 0) /* Reached the end, nothing more to resolve */
@ -957,7 +957,7 @@ static int apply_mount(
* mount source paths are always relative to the host root, hence we pass NULL as root directory to
* chase_symlinks() here. */
r = chase_symlinks(mount_entry_source(m), NULL, CHASE_TRAIL_SLASH, &chased);
r = chase_symlinks(mount_entry_source(m), NULL, CHASE_TRAIL_SLASH, &chased, NULL);
if (r == -ENOENT && m->ignore) {
log_debug_errno(r, "Path %s does not exist, ignoring.", mount_entry_source(m));
return 0;

View File

@ -946,22 +946,27 @@ static int service_load_pid_file(Service *s, bool may_warn) {
prio = may_warn ? LOG_INFO : LOG_DEBUG;
fd = chase_symlinks(s->pid_file, NULL, CHASE_OPEN|CHASE_SAFE, NULL);
if (fd == -ENOLINK) {
log_unit_full(UNIT(s), LOG_DEBUG, fd, "Potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
r = chase_symlinks(s->pid_file, NULL, CHASE_SAFE, NULL, &fd);
if (r == -ENOLINK) {
log_unit_full(UNIT(s), LOG_DEBUG, r,
"Potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
questionable_pid_file = true;
fd = chase_symlinks(s->pid_file, NULL, CHASE_OPEN, NULL);
r = chase_symlinks(s->pid_file, NULL, 0, NULL, &fd);
}
if (fd < 0)
return log_unit_full(UNIT(s), prio, fd, "Can't open PID file %s (yet?) after %s: %m", s->pid_file, service_state_to_string(s->state));
if (r < 0)
return log_unit_full(UNIT(s), prio, fd,
"Can't open PID file %s (yet?) after %s: %m", s->pid_file, service_state_to_string(s->state));
/* Let's read the PID file now that we chased it down. But we need to convert the O_PATH fd chase_symlinks() returned us into a proper fd first. */
/* Let's read the PID file now that we chased it down. But we need to convert the O_PATH fd
* chase_symlinks() returned us into a proper fd first. */
xsprintf(procfs, "/proc/self/fd/%i", fd);
r = read_one_line_file(procfs, &k);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Can't convert PID files %s O_PATH file descriptor to proper file descriptor: %m", s->pid_file);
return log_unit_error_errno(UNIT(s), r,
"Can't convert PID files %s O_PATH file descriptor to proper file descriptor: %m",
s->pid_file);
r = parse_pid(k, &pid);
if (r < 0)

View File

@ -1429,7 +1429,7 @@ static int socket_determine_selinux_label(Socket *s, char **ret) {
if (!c)
goto no_label;
r = chase_symlinks(c->path, service->exec_context.root_directory, CHASE_PREFIX_ROOT, &path);
r = chase_symlinks(c->path, service->exec_context.root_directory, CHASE_PREFIX_ROOT, &path, NULL);
if (r < 0)
goto no_label;

View File

@ -4974,7 +4974,7 @@ int unit_fail_if_noncanonical(Unit *u, const char* where) {
assert(u);
assert(where);
r = chase_symlinks(where, NULL, CHASE_NONEXISTENT, &canonical_where);
r = chase_symlinks(where, NULL, CHASE_NONEXISTENT, &canonical_where, NULL);
if (r < 0) {
log_unit_debug_errno(u, r, "Failed to check %s for symlinks, ignoring: %m", where);
return 0;

View File

@ -73,11 +73,11 @@ static int equivalent(const char *a, const char *b) {
_cleanup_free_ char *x = NULL, *y = NULL;
int r;
r = chase_symlinks(a, NULL, CHASE_TRAIL_SLASH, &x);
r = chase_symlinks(a, NULL, CHASE_TRAIL_SLASH, &x, NULL);
if (r < 0)
return r;
r = chase_symlinks(b, NULL, CHASE_TRAIL_SLASH, &y);
r = chase_symlinks(b, NULL, CHASE_TRAIL_SLASH, &y, NULL);
if (r < 0)
return r;
@ -378,7 +378,7 @@ static int should_skip_path(const char *prefix, const char *suffix) {
dirname = prefix_roota(prefix, suffix);
if (chase_symlinks(dirname, NULL, 0, &target) < 0)
if (chase_symlinks(dirname, NULL, 0, &target, NULL) < 0)
return false;
NULSTR_FOREACH(p, prefixes) {

View File

@ -563,7 +563,7 @@ static int parse_fstab(bool initrd) {
* target is the final directory. */
r = chase_symlinks(where, initrd ? "/sysroot" : NULL,
CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
&canonical_where);
&canonical_where, NULL);
if (r < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
log_debug_errno(r, "Failed to read symlink target for %s, ignoring: %m", where);
else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */

View File

@ -1086,7 +1086,7 @@ static int add_matches(sd_journal *j, char **args) {
_cleanup_free_ char *p = NULL, *t = NULL, *t2 = NULL, *interpreter = NULL;
struct stat st;
r = chase_symlinks(*i, NULL, CHASE_TRAIL_SLASH, &p);
r = chase_symlinks(*i, NULL, CHASE_TRAIL_SLASH, &p, NULL);
if (r < 0)
return log_error_errno(r, "Couldn't canonicalize path: %m");

View File

@ -146,7 +146,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
_syspath);
if (verify) {
r = chase_symlinks(_syspath, NULL, 0, &syspath);
r = chase_symlinks(_syspath, NULL, 0, &syspath, NULL);
if (r == -ENOENT)
return -ENODEV; /* the device does not exist (any more?) */
if (r < 0)
@ -157,7 +157,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
char *p;
/* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */
r = chase_symlinks("/sys", NULL, 0, &real_sys);
r = chase_symlinks("/sys", NULL, 0, &real_sys, NULL);
if (r < 0)
return log_debug_errno(r, "sd-device: Failed to chase symlink /sys: %m");

View File

@ -846,7 +846,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
if (laccess(p, F_OK) < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, &chased_src);
r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, &chased_src, NULL);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to resolve source path: %m");

View File

@ -360,7 +360,7 @@ static int parse_argv(int argc, char *argv[]) {
if (!u)
return log_oom();
r = chase_symlinks(u, NULL, 0, &arg_mount_what);
r = chase_symlinks(u, NULL, 0, &arg_mount_what, NULL);
if (r < 0)
return log_error_errno(r, "Failed to make path %s absolute: %m", u);
} else {
@ -377,7 +377,7 @@ static int parse_argv(int argc, char *argv[]) {
if (argc > optind+1) {
if (arg_transport == BUS_TRANSPORT_LOCAL) {
r = chase_symlinks(argv[optind+1], NULL, CHASE_NONEXISTENT, &arg_mount_where);
r = chase_symlinks(argv[optind+1], NULL, CHASE_NONEXISTENT, &arg_mount_where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to make path %s absolute: %m", argv[optind+1]);
} else {
@ -1004,7 +1004,7 @@ static int action_umount(
if (!u)
return log_oom();
r = chase_symlinks(u, NULL, 0, &p);
r = chase_symlinks(u, NULL, 0, &p, NULL);
if (r < 0) {
r2 = log_error_errno(r, "Failed to make path %s absolute: %m", argv[i]);
continue;

View File

@ -633,7 +633,7 @@ int mount_all(const char *dest,
if (!tmpfs_tmp && (bool)(mount_table[k].mount_settings & MOUNT_APPLY_TMPFS_TMP))
continue;
r = chase_symlinks(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where);
r = chase_symlinks(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where);
@ -734,7 +734,7 @@ static int mount_bind(const char *dest, CustomMount *m) {
if (stat(m->source, &source_st) < 0)
return log_error_errno(errno, "Failed to stat %s: %m", m->source);
r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r > 0) { /* Path exists already? */
@ -795,7 +795,7 @@ static int mount_tmpfs(
assert(dest);
assert(m);
r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */
@ -835,7 +835,7 @@ static int mount_overlay(const char *dest, CustomMount *m) {
assert(dest);
assert(m);
r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */
@ -878,7 +878,7 @@ static int mount_inaccessible(const char *dest, CustomMount *m) {
assert(dest);
assert(m);
r = chase_symlinks_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st);
r = chase_symlinks_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st, NULL);
if (r < 0) {
log_full_errno(m->graceful ? LOG_DEBUG : LOG_ERR, r, "Failed to resolve %s/%s: %m", dest, m->destination);
return m->graceful ? 0 : r;
@ -906,7 +906,7 @@ static int mount_arbitrary(const char *dest, CustomMount *m) {
assert(dest);
assert(m);
r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */

View File

@ -1668,7 +1668,7 @@ static int setup_timezone(const char *dest) {
if (m == TIMEZONE_OFF)
return 0;
r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc);
r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc, NULL);
if (r < 0) {
log_warning_errno(r, "Failed to resolve /etc path in container, ignoring: %m");
return 0;
@ -1699,7 +1699,7 @@ static int setup_timezone(const char *dest) {
return 0; /* Already pointing to the right place? Then do nothing .. */
check = strjoina(dest, "/usr/share/zoneinfo/", z);
r = chase_symlinks(check, dest, 0, NULL);
r = chase_symlinks(check, dest, 0, NULL, NULL);
if (r < 0)
log_debug_errno(r, "Timezone %s does not exist (or is not accessible) in container, not creating symlink: %m", z);
else {
@ -1726,7 +1726,7 @@ static int setup_timezone(const char *dest) {
_cleanup_free_ char *resolved = NULL;
int found;
found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved);
found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved, NULL);
if (found < 0) {
log_warning_errno(found, "Failed to resolve /etc/localtime path in container, ignoring: %m");
return 0;
@ -1832,7 +1832,7 @@ static int setup_resolv_conf(const char *dest) {
if (m == RESOLV_CONF_OFF)
return 0;
r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc);
r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc, NULL);
if (r < 0) {
log_warning_errno(r, "Failed to resolve /etc path in container, ignoring: %m");
return 0;
@ -1856,7 +1856,7 @@ static int setup_resolv_conf(const char *dest) {
_cleanup_free_ char *resolved = NULL;
int found;
found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved);
found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved, NULL);
if (found < 0) {
log_warning_errno(found, "Failed to resolve /etc/resolv.conf path in container, ignoring: %m");
return 0;
@ -2733,12 +2733,11 @@ static int chase_symlinks_and_update(char **p, unsigned flags) {
if (!*p)
return 0;
r = chase_symlinks(*p, NULL, flags, &chased);
r = chase_symlinks(*p, NULL, flags, &chased, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s: %m", *p);
free_and_replace(*p, chased);
return r; /* r might be an fd here in case we ever use CHASE_OPEN in flags */
return free_and_replace(*p, chased);
}
static int determine_uid_shift(const char *directory) {

View File

@ -67,7 +67,7 @@ static int determine_image(const char *image, bool permit_non_existing, char **r
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Operations on images by path not supported when connecting to remote systems.");
r = chase_symlinks(image, NULL, CHASE_TRAIL_SLASH | (permit_non_existing ? CHASE_NONEXISTENT : 0), ret);
r = chase_symlinks(image, NULL, CHASE_TRAIL_SLASH | (permit_non_existing ? CHASE_NONEXISTENT : 0), ret, NULL);
if (r < 0)
return log_error_errno(r, "Cannot normalize specified image path '%s': %m", image);

View File

@ -833,7 +833,7 @@ static int mount_partition(
rw = m->rw && !(flags & DISSECT_IMAGE_READ_ONLY);
if (directory) {
r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased);
r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased, NULL);
if (r < 0)
return r;
@ -909,7 +909,7 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
/* Mount the ESP to /efi if it exists. If it doesn't exist, use /boot instead, but only if it
* exists and is empty, and we didn't already mount the XBOOTLDR partition into it. */
r = chase_symlinks("/efi", where, CHASE_PREFIX_ROOT, NULL);
r = chase_symlinks("/efi", where, CHASE_PREFIX_ROOT, NULL, NULL);
if (r >= 0) {
r = mount_partition(m->partitions + PARTITION_ESP, where, "/efi", uid_shift, flags);
if (r < 0)
@ -918,7 +918,7 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
} else if (boot_mounted <= 0) {
_cleanup_free_ char *p = NULL;
r = chase_symlinks("/boot", where, CHASE_PREFIX_ROOT, &p);
r = chase_symlinks("/boot", where, CHASE_PREFIX_ROOT, &p, NULL);
if (r >= 0 && dir_is_empty(p) > 0) {
r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, flags);
if (r < 0)

View File

@ -106,7 +106,7 @@ static int unit_file_add_dir(
/* This adds [original_root]/path to dirs, if it exists. */
r = chase_symlinks(path, original_root, 0, &chased);
r = chase_symlinks(path, original_root, 0, &chased, NULL);
if (r == -ENOENT) /* Ignore -ENOENT, after all most units won't have a drop-in dir. */
return 0;
if (r == -ENAMETOOLONG) {

View File

@ -1113,7 +1113,7 @@ int image_read_metadata(Image *i) {
_cleanup_free_ char *hostname = NULL;
_cleanup_free_ char *path = NULL;
r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path, NULL);
if (r < 0 && r != -ENOENT)
log_debug_errno(r, "Failed to chase /etc/hostname in image %s: %m", i->name);
else if (r >= 0) {
@ -1124,7 +1124,7 @@ int image_read_metadata(Image *i) {
path = mfree(path);
r = chase_symlinks("/etc/machine-id", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
r = chase_symlinks("/etc/machine-id", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path, NULL);
if (r < 0 && r != -ENOENT)
log_debug_errno(r, "Failed to chase /etc/machine-id in image %s: %m", i->name);
else if (r >= 0) {
@ -1142,7 +1142,7 @@ int image_read_metadata(Image *i) {
path = mfree(path);
r = chase_symlinks("/etc/machine-info", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path);
r = chase_symlinks("/etc/machine-info", i->path, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &path, NULL);
if (r < 0 && r != -ENOENT)
log_debug_errno(r, "Failed to chase /etc/machine-info in image %s: %m", i->name);
else if (r >= 0) {

View File

@ -33,22 +33,24 @@ int path_is_os_tree(const char *path) {
int open_os_release(const char *root, char **ret_path, int *ret_fd) {
_cleanup_free_ char *q = NULL;
const char *p;
int k;
int r, fd;
FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") {
k = chase_symlinks(p, root, CHASE_PREFIX_ROOT|(ret_fd ? CHASE_OPEN : 0), (ret_path ? &q : NULL));
if (k != -ENOENT)
r = chase_symlinks(p, root, CHASE_PREFIX_ROOT,
ret_path ? &q : NULL,
ret_fd ? &fd : NULL);
if (r != -ENOENT)
break;
}
if (k < 0)
return k;
if (r < 0)
return r;
if (ret_fd) {
int real_fd;
/* Convert the O_PATH fd into a proper, readable one */
real_fd = fd_reopen(k, O_RDONLY|O_CLOEXEC|O_NOCTTY);
safe_close(k);
real_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NOCTTY);
safe_close(fd);
if (real_fd < 0)
return real_fd;

View File

@ -52,7 +52,7 @@ int switch_root(const char *new_root,
}
/* Determine where we shall place the old root after the transition */
r = chase_symlinks(old_root_after, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved_old_root_after);
r = chase_symlinks(old_root_after, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved_old_root_after, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, old_root_after);
if (r == 0) /* Doesn't exist yet. Let's create it */
@ -68,7 +68,7 @@ int switch_root(const char *new_root,
FOREACH_STRING(i, "/sys", "/dev", "/run", "/proc") {
_cleanup_free_ char *chased = NULL;
r = chase_symlinks(i, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &chased);
r = chase_symlinks(i, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &chased, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, i);
if (r > 0) {

View File

@ -303,7 +303,7 @@ int unit_file_build_name_map(
}
/* Get rid of "." and ".." components in target path */
r = chase_symlinks(target, lp->root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified);
r = chase_symlinks(target, lp->root_dir, CHASE_NOFOLLOW | CHASE_NONEXISTENT, &simplified, NULL);
if (r < 0) {
log_warning_errno(r, "Failed to resolve symlink %s pointing to %s, ignoring: %m",
filename, target);

View File

@ -2520,7 +2520,7 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **re
if (!path)
return log_oom();
r = chase_symlinks(path, arg_root, 0, &lpath);
r = chase_symlinks(path, arg_root, 0, &lpath, NULL);
if (r == -ENOENT)
continue;
if (r == -ENOMEM)

View File

@ -8,21 +8,23 @@
static char *arg_root = NULL;
static int arg_flags = 0;
static bool arg_open = false;
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_ROOT = 0x1000,
ARG_OPEN,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "root", required_argument, NULL, ARG_ROOT },
{ "open", no_argument, NULL, ARG_OPEN },
{ "prefix-root", no_argument, NULL, CHASE_PREFIX_ROOT },
{ "nonexistent", no_argument, NULL, CHASE_NONEXISTENT },
{ "no_autofs", no_argument, NULL, CHASE_NO_AUTOFS },
{ "safe", no_argument, NULL, CHASE_SAFE },
{ "open", no_argument, NULL, CHASE_OPEN },
{ "trail-slash", no_argument, NULL, CHASE_TRAIL_SLASH },
{ "step", no_argument, NULL, CHASE_STEP },
{ "nofollow", no_argument, NULL, CHASE_NOFOLLOW },
@ -51,11 +53,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_root = optarg;
break;
case ARG_OPEN:
arg_open = true;
break;
case CHASE_PREFIX_ROOT:
case CHASE_NONEXISTENT:
case CHASE_NO_AUTOFS:
case CHASE_SAFE:
case CHASE_OPEN:
case CHASE_TRAIL_SLASH:
case CHASE_STEP:
case CHASE_NOFOLLOW:
@ -89,18 +94,21 @@ static int run(int argc, char **argv) {
for (int i = optind; i < argc; i++) {
_cleanup_free_ char *p = NULL;
_cleanup_close_ int fd = -1;
printf("%s ", argv[i]);
fflush(stdout);
r = chase_symlinks(argv[i], arg_root, arg_flags, &p);
r = chase_symlinks(argv[i], arg_root, arg_flags, &p, arg_open ? &fd : NULL);
if (r < 0)
log_error_errno(r, "failed: %m");
else
else {
log_info("→ %s", p);
if (FLAGS_SET(arg_flags, CHASE_OPEN))
safe_close(r);
if (arg_open)
assert(fd >= 0);
else
assert(fd == -1);
}
}
return 0;

View File

@ -130,7 +130,7 @@ static void test_copy_tree(void) {
assert_se(f = strjoin(original_dir, *p));
assert_se(l = strjoin(copy_dir, *link));
assert_se(chase_symlinks(l, NULL, 0, &target) == 1);
assert_se(chase_symlinks(l, NULL, 0, &target, NULL) == 1);
assert_se(path_equal(f, target));
}

View File

@ -61,45 +61,45 @@ static void test_chase_symlinks(void) {
/* Paths that use symlinks underneath the "root" */
r = chase_symlinks(p, NULL, 0, &result);
r = chase_symlinks(p, NULL, 0, &result, NULL);
assert_se(r > 0);
assert_se(path_equal(result, "/usr"));
result = mfree(result);
pslash = strjoina(p, "/");
r = chase_symlinks(pslash, NULL, 0, &result);
r = chase_symlinks(pslash, NULL, 0, &result, NULL);
assert_se(r > 0);
assert_se(path_equal(result, "/usr/"));
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
r = chase_symlinks(p, temp, 0, &result, NULL);
assert_se(r == -ENOENT);
r = chase_symlinks(pslash, temp, 0, &result);
r = chase_symlinks(pslash, temp, 0, &result, NULL);
assert_se(r == -ENOENT);
q = strjoina(temp, "/usr");
r = chase_symlinks(p, temp, CHASE_NONEXISTENT, &result);
r = chase_symlinks(p, temp, CHASE_NONEXISTENT, &result, NULL);
assert_se(r == 0);
assert_se(path_equal(result, q));
result = mfree(result);
qslash = strjoina(q, "/");
r = chase_symlinks(pslash, temp, CHASE_NONEXISTENT, &result);
r = chase_symlinks(pslash, temp, CHASE_NONEXISTENT, &result, NULL);
assert_se(r == 0);
assert_se(path_equal(result, qslash));
result = mfree(result);
assert_se(mkdir(q, 0700) >= 0);
r = chase_symlinks(p, temp, 0, &result);
r = chase_symlinks(p, temp, 0, &result, NULL);
assert_se(r > 0);
assert_se(path_equal(result, q));
result = mfree(result);
r = chase_symlinks(pslash, temp, 0, &result);
r = chase_symlinks(pslash, temp, 0, &result, NULL);
assert_se(r > 0);
assert_se(path_equal(result, qslash));
result = mfree(result);
@ -107,12 +107,12 @@ static void test_chase_symlinks(void) {
p = strjoina(temp, "/slash");
assert_se(symlink("/", p) >= 0);
r = chase_symlinks(p, NULL, 0, &result);
r = chase_symlinks(p, NULL, 0, &result, NULL);
assert_se(r > 0);
assert_se(path_equal(result, "/"));
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
r = chase_symlinks(p, temp, 0, &result, NULL);
assert_se(r > 0);
assert_se(path_equal(result, temp));
result = mfree(result);
@ -122,21 +122,21 @@ static void test_chase_symlinks(void) {
p = strjoina(temp, "/6dots");
assert_se(symlink("../../..", p) >= 0);
r = chase_symlinks(p, temp, 0, &result);
r = chase_symlinks(p, temp, 0, &result, NULL);
assert_se(r > 0 && path_equal(result, temp));
result = mfree(result);
p = strjoina(temp, "/6dotsusr");
assert_se(symlink("../../../usr", p) >= 0);
r = chase_symlinks(p, temp, 0, &result);
r = chase_symlinks(p, temp, 0, &result, NULL);
assert_se(r > 0 && path_equal(result, q));
result = mfree(result);
p = strjoina(temp, "/top/8dotsusr");
assert_se(symlink("../../../../usr", p) >= 0);
r = chase_symlinks(p, temp, 0, &result);
r = chase_symlinks(p, temp, 0, &result, NULL);
assert_se(r > 0 && path_equal(result, q));
result = mfree(result);
@ -145,12 +145,12 @@ static void test_chase_symlinks(void) {
p = strjoina(temp, "/slashslash");
assert_se(symlink("///usr///", p) >= 0);
r = chase_symlinks(p, NULL, 0, &result);
r = chase_symlinks(p, NULL, 0, &result, NULL);
assert_se(r > 0);
assert_se(path_equal(result, "/usr"));
result = mfree(result);
r = chase_symlinks(p, temp, 0, &result);
r = chase_symlinks(p, temp, 0, &result, NULL);
assert_se(r > 0);
assert_se(path_equal(result, q));
result = mfree(result);
@ -169,48 +169,48 @@ static void test_chase_symlinks(void) {
assert_se(symlink("/", p) >= 0);
/* Fail when user-owned directories contain root-owned subdirectories. */
r = chase_symlinks(p, temp, CHASE_SAFE, &result);
r = chase_symlinks(p, temp, CHASE_SAFE, &result, NULL);
assert_se(r == -ENOLINK);
result = mfree(result);
/* Allow this when the user-owned directories are all in the "root". */
r = chase_symlinks(p, q, CHASE_SAFE, &result);
r = chase_symlinks(p, q, CHASE_SAFE, &result, NULL);
assert_se(r > 0);
result = mfree(result);
}
/* Paths using . */
r = chase_symlinks("/etc/./.././", NULL, 0, &result);
r = chase_symlinks("/etc/./.././", NULL, 0, &result, NULL);
assert_se(r > 0);
assert_se(path_equal(result, "/"));
result = mfree(result);
r = chase_symlinks("/etc/./.././", "/etc", 0, &result);
r = chase_symlinks("/etc/./.././", "/etc", 0, &result, NULL);
assert_se(r > 0 && path_equal(result, "/etc"));
result = mfree(result);
r = chase_symlinks("/../.././//../../etc", NULL, 0, &result);
r = chase_symlinks("/../.././//../../etc", NULL, 0, &result, NULL);
assert_se(r > 0);
assert_se(streq(result, "/etc"));
result = mfree(result);
r = chase_symlinks("/../.././//../../test-chase.fsldajfl", NULL, CHASE_NONEXISTENT, &result);
r = chase_symlinks("/../.././//../../test-chase.fsldajfl", NULL, CHASE_NONEXISTENT, &result, NULL);
assert_se(r == 0);
assert_se(streq(result, "/test-chase.fsldajfl"));
result = mfree(result);
r = chase_symlinks("/../.././//../../etc", "/", CHASE_PREFIX_ROOT, &result);
r = chase_symlinks("/../.././//../../etc", "/", CHASE_PREFIX_ROOT, &result, NULL);
assert_se(r > 0);
assert_se(streq(result, "/etc"));
result = mfree(result);
r = chase_symlinks("/../.././//../../test-chase.fsldajfl", "/", CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &result);
r = chase_symlinks("/../.././//../../test-chase.fsldajfl", "/", CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &result, NULL);
assert_se(r == 0);
assert_se(streq(result, "/test-chase.fsldajfl"));
result = mfree(result);
r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result, NULL);
assert_se(r == -ENOTDIR);
result = mfree(result);
@ -218,25 +218,25 @@ static void test_chase_symlinks(void) {
p = strjoina(temp, "/recursive-symlink");
assert_se(symlink("recursive-symlink", p) >= 0);
r = chase_symlinks(p, NULL, 0, &result);
r = chase_symlinks(p, NULL, 0, &result, NULL);
assert_se(r == -ELOOP);
/* Path which doesn't exist */
p = strjoina(temp, "/idontexist");
r = chase_symlinks(p, NULL, 0, &result);
r = chase_symlinks(p, NULL, 0, &result, NULL);
assert_se(r == -ENOENT);
r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result, NULL);
assert_se(r == 0);
assert_se(path_equal(result, p));
result = mfree(result);
p = strjoina(temp, "/idontexist/meneither");
r = chase_symlinks(p, NULL, 0, &result);
r = chase_symlinks(p, NULL, 0, &result, NULL);
assert_se(r == -ENOENT);
r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result, NULL);
assert_se(r == 0);
assert_se(path_equal(result, p));
result = mfree(result);
@ -244,17 +244,17 @@ static void test_chase_symlinks(void) {
/* Path which doesn't exist, but contains weird stuff */
p = strjoina(temp, "/idontexist/..");
r = chase_symlinks(p, NULL, 0, &result);
r = chase_symlinks(p, NULL, 0, &result, NULL);
assert_se(r == -ENOENT);
r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result, NULL);
assert_se(r == -ENOENT);
p = strjoina(temp, "/target");
q = strjoina(temp, "/top");
assert_se(symlink(q, p) >= 0);
p = strjoina(temp, "/target/idontexist");
r = chase_symlinks(p, NULL, 0, &result);
r = chase_symlinks(p, NULL, 0, &result, NULL);
assert_se(r == -ENOENT);
if (geteuid() == 0) {
@ -264,30 +264,30 @@ static void test_chase_symlinks(void) {
q = strjoina(p, "/priv2");
assert_se(mkdir(q, 0755) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL, NULL) >= 0);
assert_se(chown(q, UID_NOBODY, GID_NOBODY) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL, NULL) >= 0);
assert_se(chown(p, UID_NOBODY, GID_NOBODY) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL, NULL) >= 0);
assert_se(chown(q, 0, 0) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL, NULL) == -ENOLINK);
assert_se(rmdir(q) >= 0);
assert_se(symlink("/etc/passwd", q) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL, NULL) == -ENOLINK);
assert_se(chown(p, 0, 0) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL, NULL) >= 0);
}
p = strjoina(temp, "/machine-id-test");
assert_se(symlink("/usr/../etc/./machine-id", p) >= 0);
pfd = chase_symlinks(p, NULL, CHASE_OPEN, NULL);
if (pfd != -ENOENT) {
r = chase_symlinks(p, NULL, 0, NULL, &pfd);
if (r != -ENOENT) {
_cleanup_close_ int fd = -1;
sd_id128_t a, b;
@ -307,8 +307,9 @@ static void test_chase_symlinks(void) {
p = strjoina(temp, "/target");
q = strjoina(temp, "/symlink");
assert_se(symlink(p, q) >= 0);
pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result);
assert_se(pfd > 0);
r = chase_symlinks(q, NULL, CHASE_NOFOLLOW, &result, &pfd);
assert_se(r >= 0);
assert_se(pfd >= 0);
assert_se(path_equal(result, q));
assert_se(fstat(pfd, &st) >= 0);
assert_se(S_ISLNK(st.st_mode));
@ -319,8 +320,9 @@ static void test_chase_symlinks(void) {
assert_se(symlink("s2", q) >= 0);
p = strjoina(temp, "/s2");
assert_se(symlink("nonexistent", p) >= 0);
pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result);
assert_se(pfd > 0);
r = chase_symlinks(q, NULL, CHASE_NOFOLLOW, &result, &pfd);
assert_se(r >= 0);
assert_se(pfd >= 0);
assert_se(path_equal(result, q));
assert_se(fstat(pfd, &st) >= 0);
assert_se(S_ISLNK(st.st_mode));
@ -329,42 +331,42 @@ static void test_chase_symlinks(void) {
/* Test CHASE_ONE */
p = strjoina(temp, "/start");
r = chase_symlinks(p, NULL, CHASE_STEP, &result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result, NULL);
assert_se(r == 0);
p = strjoina(temp, "/top/dot/dotdota");
assert_se(streq(p, result));
result = mfree(result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result, NULL);
assert_se(r == 0);
p = strjoina(temp, "/top/./dotdota");
assert_se(streq(p, result));
result = mfree(result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result, NULL);
assert_se(r == 0);
p = strjoina(temp, "/top/../a");
assert_se(streq(p, result));
result = mfree(result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result, NULL);
assert_se(r == 0);
p = strjoina(temp, "/a");
assert_se(streq(p, result));
result = mfree(result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result, NULL);
assert_se(r == 0);
p = strjoina(temp, "/b");
assert_se(streq(p, result));
result = mfree(result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result);
r = chase_symlinks(p, NULL, CHASE_STEP, &result, NULL);
assert_se(r == 0);
assert_se(streq("/usr", result));
result = mfree(result);
r = chase_symlinks("/usr", NULL, CHASE_STEP, &result);
r = chase_symlinks("/usr", NULL, CHASE_STEP, &result, NULL);
assert_se(r > 0);
assert_se(streq("/usr", result));
result = mfree(result);

View File

@ -859,7 +859,7 @@ shortcut:
static int path_open_parent_safe(const char *path) {
_cleanup_free_ char *dn = NULL;
int fd;
int r, fd;
if (path_equal(path, "/") || !path_is_normalized(path))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@ -870,15 +870,15 @@ static int path_open_parent_safe(const char *path) {
if (!dn)
return log_oom();
fd = chase_symlinks(dn, arg_root, CHASE_OPEN|CHASE_SAFE|CHASE_WARN, NULL);
if (fd < 0 && fd != -ENOLINK)
return log_error_errno(fd, "Failed to validate path %s: %m", path);
r = chase_symlinks(dn, arg_root, CHASE_SAFE|CHASE_WARN, NULL, &fd);
if (r < 0 && r != -ENOLINK)
return log_error_errno(r, "Failed to validate path %s: %m", path);
return fd;
return r < 0 ? r : fd;
}
static int path_open_safe(const char *path) {
int fd;
int r, fd;
/* path_open_safe() returns a file descriptor opened with O_PATH after
* verifying that the path doesn't contain unsafe transitions, except
@ -891,11 +891,11 @@ static int path_open_safe(const char *path) {
"Failed to open invalid path '%s'.",
path);
fd = chase_symlinks(path, arg_root, CHASE_OPEN|CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW, NULL);
if (fd < 0 && fd != -ENOLINK)
return log_error_errno(fd, "Failed to validate path %s: %m", path);
r = chase_symlinks(path, arg_root, CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW, NULL, &fd);
if (r < 0 && r != -ENOLINK)
return log_error_errno(r, "Failed to validate path %s: %m", path);
return fd;
return r < 0 ? r : fd;
}
static int path_set_perms(Item *i, const char *path) {
@ -2257,7 +2257,7 @@ static int process_item(Item *i, OperationMask operation) {
i->done |= operation;
r = chase_symlinks(i->path, arg_root, CHASE_NO_AUTOFS|CHASE_WARN, NULL);
r = chase_symlinks(i->path, arg_root, CHASE_NO_AUTOFS|CHASE_WARN, NULL, NULL);
if (r == -EREMOTE) {
log_notice_errno(r, "Skipping %s", i->path);
return 0;

View File

@ -119,7 +119,7 @@ static int get_virtfn_info(sd_device *dev, struct netnames *names, struct virtfn
/* Check if this is a virtual function. */
physfn_link_file = strjoina(syspath, "/physfn");
r = chase_symlinks(physfn_link_file, NULL, 0, &physfn_pci_syspath);
r = chase_symlinks(physfn_link_file, NULL, 0, &physfn_pci_syspath, NULL);
if (r < 0)
return r;
@ -143,7 +143,7 @@ static int get_virtfn_info(sd_device *dev, struct netnames *names, struct virtfn
if (!virtfn_link_file)
return -ENOMEM;
if (chase_symlinks(virtfn_link_file, NULL, 0, &virtfn_pci_syspath) < 0)
if (chase_symlinks(virtfn_link_file, NULL, 0, &virtfn_pci_syspath, NULL) < 0)
continue;
if (streq(syspath, virtfn_pci_syspath)) {

View File

@ -21,7 +21,7 @@ static int make_volatile(const char *path) {
assert(path);
r = chase_symlinks("/usr", path, CHASE_PREFIX_ROOT, &old_usr);
r = chase_symlinks("/usr", path, CHASE_PREFIX_ROOT, &old_usr, NULL);
if (r < 0)
return log_error_errno(r, "/usr not available in old root: %m");