From 2f30582bd3d00ce582d190ddb379e46e0a67f813 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Nov 2016 21:35:21 +0100 Subject: [PATCH] tree-wide: stop using canonicalize_file_name(), use chase_symlinks() instead Let's use chase_symlinks() everywhere, and stop using GNU canonicalize_file_name() everywhere. For most cases this should not change behaviour, however increase exposure of our function to get better tested. Most importantly in a few cases (most notably nspawn) it can take the correct root directory into account when chasing symlinks. --- src/basic/fs-util.c | 26 +++++++++---------- src/basic/fs-util.h | 2 +- src/basic/mount-util.c | 16 ++++++------ src/basic/mount-util.h | 2 +- src/basic/path-util.c | 55 ++++++++++++++++++++++++----------------- src/basic/path-util.h | 4 +-- src/core/mount-setup.c | 2 +- src/login/logind-user.c | 2 +- 8 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index f288848c9..0d96302be 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -225,25 +225,25 @@ int readlink_and_make_absolute(const char *p, char **r) { return 0; } -int readlink_and_canonicalize(const char *p, char **r) { +int readlink_and_canonicalize(const char *p, const char *root, char **ret) { char *t, *s; - int j; + int r; assert(p); - assert(r); + assert(ret); - j = readlink_and_make_absolute(p, &t); - if (j < 0) - return j; + r = readlink_and_make_absolute(p, &t); + if (r < 0) + return r; - s = canonicalize_file_name(t); - if (s) { + r = chase_symlinks(t, root, &s); + if (r < 0) + /* If we can't follow up, then let's return the original string, slightly cleaned up. */ + *ret = path_kill_slashes(t); + else { + *ret = s; free(t); - *r = s; - } else - *r = t; - - path_kill_slashes(*r); + } return 0; } diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 871f7209f..de4bb861e 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -42,7 +42,7 @@ int readlink_malloc(const char *p, char **r); #if 0 /// UNNEEDED by elogind int readlink_value(const char *p, char **ret); int readlink_and_make_absolute(const char *p, char **r); -int readlink_and_canonicalize(const char *p, char **r); +int readlink_and_canonicalize(const char *p, const char *root, char **r); int readlink_and_make_absolute_root(const char *root, const char *path, char **ret); #endif // 0 diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 051b14b17..477342e71 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -161,7 +161,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { fallback_fdinfo: r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); - if (r == -EOPNOTSUPP) + if (IN_SET(r, -EOPNOTSUPP, -EACCES)) goto fallback_fstat; if (r < 0) return r; @@ -204,9 +204,10 @@ fallback_fstat: } /* flags can be AT_SYMLINK_FOLLOW or 0 */ -int path_is_mount_point(const char *t, int flags) { - _cleanup_close_ int fd = -1; +int path_is_mount_point(const char *t, const char *root, int flags) { _cleanup_free_ char *canonical = NULL, *parent = NULL; + _cleanup_close_ int fd = -1; + int r; assert(t); @@ -218,9 +219,9 @@ int path_is_mount_point(const char *t, 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) { - canonical = canonicalize_file_name(t); - if (!canonical) - return -errno; + r = chase_symlinks(t, root, &canonical); + if (r < 0) + return r; t = canonical; } @@ -473,7 +474,7 @@ int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) { return r; /* Deal with mount points that are obstructed by a later mount */ - r = path_is_mount_point(x, 0); + r = path_is_mount_point(x, NULL, 0); if (r == -ENOENT || r == 0) continue; if (r < 0) @@ -525,6 +526,7 @@ bool fstype_is_network(const char *fstype) { "glusterfs\0" "pvfs2\0" /* OrangeFS */ "ocfs2\0" + "lustre\0" ; const char *x; diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index d538ea953..ea887e162 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -30,7 +30,7 @@ #include "missing.h" int fd_is_mount_point(int fd, const char *filename, int flags); -int path_is_mount_point(const char *path, int flags); +int path_is_mount_point(const char *path, const char *root, int flags); #if 0 /// UNNEEDED by elogind int repeat_unmount(const char *path, int flags); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 25a956e97..9dd073338 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -222,10 +222,11 @@ int path_strv_make_absolute_cwd(char **l) { } #endif // 0 -char **path_strv_resolve(char **l, const char *prefix) { +char **path_strv_resolve(char **l, const char *root) { char **s; unsigned k = 0; bool enomem = false; + int r; if (strv_isempty(l)) return l; @@ -235,17 +236,17 @@ char **path_strv_resolve(char **l, const char *prefix) { * changes on failure. */ STRV_FOREACH(s, l) { - char *t, *u; _cleanup_free_ char *orig = NULL; + char *t, *u; if (!path_is_absolute(*s)) { free(*s); continue; } - if (prefix) { + if (root) { orig = *s; - t = strappend(prefix, orig); + t = prefix_root(root, orig); if (!t) { enomem = true; continue; @@ -253,28 +254,26 @@ char **path_strv_resolve(char **l, const char *prefix) { } else t = *s; - errno = 0; - u = canonicalize_file_name(t); - if (!u) { - if (errno == ENOENT) { - if (prefix) { - u = orig; - orig = NULL; - free(t); - } else - u = t; - } else { + r = chase_symlinks(t, root, &u); + if (r == -ENOENT) { + if (root) { + u = orig; + orig = NULL; free(t); - if (errno == ENOMEM || errno == 0) - enomem = true; + } else + u = t; + } else if (r < 0) { + free(t); - continue; - } - } else if (prefix) { + if (r == -ENOMEM) + enomem = true; + + continue; + } else if (root) { char *x; free(t); - x = path_startswith(u, prefix); + x = path_startswith(u, root); if (x) { /* restore the slash if it was lost */ if (!startswith(x, "/")) @@ -306,12 +305,12 @@ char **path_strv_resolve(char **l, const char *prefix) { return l; } -char **path_strv_resolve_uniq(char **l, const char *prefix) { +char **path_strv_resolve_uniq(char **l, const char *root) { if (strv_isempty(l)) return l; - if (!path_strv_resolve(l, prefix)) + if (!path_strv_resolve(l, root)) return NULL; return strv_uniq(l); @@ -356,6 +355,16 @@ char* path_startswith(const char *path, const char *prefix) { assert(path); assert(prefix); + /* Returns a pointer to the start of the first component after the parts matched by + * the prefix, iff + * - both paths are absolute or both paths are relative, + * and + * - each component in prefix in turn matches a component in path at the same position. + * An empty string will be returned when the prefix and path are equivalent. + * + * Returns NULL otherwise. + */ + if ((path[0] == '/') != (prefix[0] == '/')) return NULL; diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 605485665..4d284d23c 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -76,8 +76,8 @@ static inline bool path_equal_ptr(const char *a, const char *b) { #if 0 /// UNNEEDED by elogind int path_strv_make_absolute_cwd(char **l); #endif // 0 -char** path_strv_resolve(char **l, const char *prefix); -char** path_strv_resolve_uniq(char **l, const char *prefix); +char** path_strv_resolve(char **l, const char *root); +char** path_strv_resolve_uniq(char **l, const char *root); #if 0 /// UNNEEDED by elogind int find_binary(const char *name, char **filename); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index c551fa62b..7dfaf27df 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -174,7 +174,7 @@ static int mount_one(const MountPoint *p, bool relabel) { if (relabel) (void) label_fix(p->where, true, true); - r = path_is_mount_point(p->where, AT_SYMLINK_FOLLOW); + r = path_is_mount_point(p->where, NULL, AT_SYMLINK_FOLLOW); if (r < 0 && r != -ENOENT) { log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, r, "Failed to determine whether %s is a mount point: %m", p->where); return (p->mode & MNT_FATAL) ? r : 0; diff --git a/src/login/logind-user.c b/src/login/logind-user.c index c1fd75a82..b8abc6af0 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -347,7 +347,7 @@ static int user_mkdir_runtime_path(User *u) { if (r < 0) return log_error_errno(r, "Failed to create /run/user: %m"); - if (path_is_mount_point(u->runtime_path, 0) <= 0) { + if (path_is_mount_point(u->runtime_path, NULL, 0) <= 0) { _cleanup_free_ char *t = NULL; (void) mkdir_label(u->runtime_path, 0700); -- 2.30.2