From: Zbigniew Jędrzejewski-Szmek Date: Thu, 24 Oct 2019 08:33:20 +0000 (+0200) Subject: basic/fs-util: change CHASE_OPEN flag into a separate output parameter X-Git-Tag: v244-rc1~162 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a5648b809457d120500b2acb18b31e2168a4817a;p=thirdparty%2Fsystemd.git 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.) --- diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index a92241ca02a..d20b9a5df55 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -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; } diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index fa0f0de9a34..78d68be9fd8 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -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) { diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 6b82eab6409..1f318252a98 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -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) diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index d3b8e44f184..a79377f05d0 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -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; diff --git a/src/basic/path-util.c b/src/basic/path-util.c index b9544b4bacc..98b6d0617f2 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -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); diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 2cd722c1064..4572e004bbb 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -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) { diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 035011e34f9..d98ec32a0bf 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -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); diff --git a/src/core/namespace.c b/src/core/namespace.c index 973b64007cf..f6f7736819b 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -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; diff --git a/src/core/service.c b/src/core/service.c index 256ca46fd88..525ce428901 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -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) diff --git a/src/core/socket.c b/src/core/socket.c index 71ab3c647f9..285aa641d3c 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -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; diff --git a/src/core/unit.c b/src/core/unit.c index 58c99d9e073..4fcc142ae9a 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -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; diff --git a/src/delta/delta.c b/src/delta/delta.c index bc11aa828a6..cd33850b969 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -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) { diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 76270aec17f..026a25f5758 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -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 */ diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 6d6bb1cf63c..6d9b5cfc2fb 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -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"); diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index c4a7f2f3d34..4a5e8ff944a 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -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"); diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 0d58b5eb8b6..c2747112d4f 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -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"); diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index 457ba4ea16f..9f0220a75e7 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -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; diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 2f842754a4f..6407503c4c9 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -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? */ diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 40a7de981ac..7760bcaa2d3 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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) { diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index 2f8b0254c80..06ab7735ade 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -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); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index a54714169e0..3e754649669 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -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) diff --git a/src/shared/dropin.c b/src/shared/dropin.c index 2f67a44bf0b..7328b7adde5 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -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) { diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 70073741927..cceed58f744 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -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) { diff --git a/src/shared/os-util.c b/src/shared/os-util.c index 2191a610ae2..b2af8535f9c 100644 --- a/src/shared/os-util.c +++ b/src/shared/os-util.c @@ -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; diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index f721aff7607..a807826378d 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -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) { diff --git a/src/shared/unit-file.c b/src/shared/unit-file.c index b015ff93381..28cd3c86009 100644 --- a/src/shared/unit-file.c +++ b/src/shared/unit-file.c @@ -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); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index e4b85d906ca..05013484ad1 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -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) diff --git a/src/test/test-chase-symlinks.c b/src/test/test-chase-symlinks.c index 013b36e2a7a..0b7dd8764f0 100644 --- a/src/test/test-chase-symlinks.c +++ b/src/test/test-chase-symlinks.c @@ -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; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 5f7b9e5ce8d..ffabf95663c 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -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)); } diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index 7cf4f4976bc..ac8b95aece0 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -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); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 19a2aa6f21e..fae949863a4 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -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; diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index b82fd884972..e6d4659d9f7 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -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)) { diff --git a/src/volatile-root/volatile-root.c b/src/volatile-root/volatile-root.c index d1193a7a24a..af78a87d6fe 100644 --- a/src/volatile-root/volatile-root.c +++ b/src/volatile-root/volatile-root.c @@ -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");