diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index c112f8dbad..be22d6a04f 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -1113,8 +1113,6 @@ int fds_are_same_mount(int fd1, int fd2) { int mntid; r = path_get_mnt_id_at_fallback(fd1, "", &mntid); - if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) - return true; /* skip the mount ID check */ if (r < 0) return r; assert(mntid >= 0); @@ -1127,8 +1125,6 @@ int fds_are_same_mount(int fd1, int fd2) { int mntid; r = path_get_mnt_id_at_fallback(fd2, "", &mntid); - if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) - return true; /* skip the mount ID check */ if (r < 0) return r; assert(mntid >= 0); diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 5ee7417eeb..eb031a0ccd 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -163,3 +163,12 @@ static inline int xopenat_lock(int dir_fd, const char *path, int open_flags, Loc int link_fd(int fd, int newdirfd, const char *newpath); int linkat_replace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); + +static inline int at_flags_normalize_nofollow(int flags) { + if (FLAGS_SET(flags, AT_SYMLINK_FOLLOW)) { + assert(!FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW)); + flags &= ~AT_SYMLINK_FOLLOW; + } else + flags |= AT_SYMLINK_NOFOLLOW; + return flags; +} diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index 15655cc075..aac8b19430 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -37,10 +37,10 @@ #define ORIGINAL_MAX_HANDLE_SZ 128 bool is_name_to_handle_at_fatal_error(int err) { - /* name_to_handle_at() can return "acceptable" errors that are due to the context. For example the - * kernel does not support name_to_handle_at() at all (ENOSYS), or the syscall was blocked - * (EACCES/EPERM; maybe through seccomp, because we are running inside of a container), or the mount - * point is not triggered yet (EOVERFLOW, think autofs+nfs4), or some general name_to_handle_at() + /* name_to_handle_at() can return "acceptable" errors that are due to the context. For example + * the file system does not support name_to_handle_at() (EOPNOTSUPP), or the syscall was blocked + * (EACCES/EPERM; maybe through seccomp, because we are running inside of a container), or + * the mount point is not triggered yet (EOVERFLOW, think autofs+nfs4), or some general name_to_handle_at() * flakiness (EINVAL). However other errors are not supposed to happen and therefore are considered * fatal ones. */ @@ -137,9 +137,7 @@ int name_to_handle_at_try_fid( * (i.e. older than Linux 6.5). */ r = name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags | AT_HANDLE_FID); - if (r >= 0) - return r; - if (is_name_to_handle_at_fatal_error(r)) + if (r >= 0 || is_name_to_handle_at_fatal_error(r)) return r; return name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags & ~AT_HANDLE_FID); @@ -149,11 +147,10 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mn char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *fdinfo = NULL; _cleanup_close_ int subfd = -EBADF; - char *p; int r; - assert(ret_mnt_id); assert((flags & ~(AT_SYMLINK_FOLLOW|AT_EMPTY_PATH)) == 0); + assert(ret_mnt_id); if ((flags & AT_EMPTY_PATH) && isempty(filename)) xsprintf(path, "/proc/self/fdinfo/%i", fd); @@ -166,16 +163,16 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mn } r = read_full_virtual_file(path, &fdinfo, NULL); - if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ - return proc_mounted() > 0 ? -EOPNOTSUPP : -ENOSYS; + if (r == -ENOENT) + return proc_fd_enoent_errno(); if (r < 0) return r; - p = find_line_startswith(fdinfo, "mnt_id:"); - if (!p) /* The mnt_id field is a relatively new addition */ - return -EOPNOTSUPP; + char *p = find_line_startswith(fdinfo, "mnt_id:"); + if (!p) + return -EBADMSG; - p += strspn(p, WHITESPACE); + p = skip_leading_chars(p, /* bad = */ NULL); p[strcspn(p, WHITESPACE)] = 0; return safe_atoi(p, ret_mnt_id); @@ -215,28 +212,36 @@ bool file_handle_equal(const struct file_handle *a, const struct file_handle *b) return memcmp_nn(a->f_handle, a->handle_bytes, b->f_handle, b->handle_bytes) == 0; } -int fd_is_mount_point(int fd, const char *filename, int flags) { - _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL; - int mount_id = -1, mount_id_parent = -1; - bool nosupp = false, check_st_dev = true; - STRUCT_STATX_DEFINE(sx); - struct stat a, b; +int is_mount_point_at(int fd, const char *filename, int flags) { + bool fd_is_self; int r; - assert(fd >= 0); + assert(fd >= 0 || fd == AT_FDCWD); assert((flags & ~AT_SYMLINK_FOLLOW) == 0); - if (!filename) { - /* If the file name is specified as NULL we'll see if the specified 'fd' is a mount - * point. That's only supported if the kernel supports statx(), or if the inode specified via - * 'fd' refers to a directory. Otherwise, we'll have to fail (ENOTDIR), because we have no - * kernel API to query the information we need. */ - flags |= AT_EMPTY_PATH; - filename = ""; - } else if (!filename_possibly_with_slash_suffix(filename)) - /* Insist that the specified filename is actually a filename, and not a path, i.e. some inode further - * up or down the tree then immediately below the specified directory fd. */ - return -EINVAL; + if (isempty(filename)) { + if (fd == AT_FDCWD) + filename = "."; + else { + /* If the file name is empty we'll see if the specified 'fd' is a mount point. + * That's only supported if the kernel supports statx(), or if the inode specified + * via 'fd' refers to a directory. Otherwise, we'll have to fail (ENOTDIR), because + * we have no kernel API to query the information we need. */ + flags |= AT_EMPTY_PATH; + filename = ""; + } + + fd_is_self = true; + } else if (STR_IN_SET(filename, ".", "./")) + fd_is_self = true; + else { + /* Insist that the specified filename is actually a filename, and not a path, i.e. some inode + * further up or down the tree then immediately below the specified directory fd. */ + if (!filename_possibly_with_slash_suffix(filename)) + return -EINVAL; + + fd_is_self = false; + } /* First we will try statx()' STATX_ATTR_MOUNT_ROOT attribute, which is our ideal API, available * since kernel 5.8. @@ -249,18 +254,17 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { * If that didn't work we will try to read the mount id from /proc/self/fdinfo/. This is almost * as good as name_to_handle_at(), however, does not return the opaque file handle. The opaque file * handle is pretty useful to detect the root directory, which we should always consider a mount - * point. Hence we use this only as fallback. Exporting the mnt_id in fdinfo is a pretty recent - * kernel addition. + * point. Hence we use this only as fallback. * - * As last fallback we do traditional fstat() based st_dev comparisons. This is how things were - * traditionally done, but unionfs breaks this since it exposes file systems with a variety of st_dev - * reported. Also, btrfs subvolumes have different st_dev, even though they aren't real mounts of - * their own. */ + * Note that traditionally the check is done via fstat()-based st_dev comparisons. However, various + * file systems don't guarantee same st_dev across single fs anymore, e.g. unionfs exposes file systems + * with a variety of st_dev reported. Also, btrfs subvolumes have different st_dev, even though + * they aren't real mounts of their own. */ - if (statx(fd, - filename, - (FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : AT_SYMLINK_NOFOLLOW) | - (flags & AT_EMPTY_PATH) | + STRUCT_STATX_DEFINE(sx); + + if (statx(fd, filename, + at_flags_normalize_nofollow(flags) | AT_NO_AUTOMOUNT | /* don't trigger automounts – mounts are a local concept, hence no need to trigger automounts to determine STATX_ATTR_MOUNT_ROOT */ AT_STATX_DONT_SYNC, /* don't go to the network for this – for similar reasons */ STATX_TYPE, @@ -274,6 +278,10 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { } else if (FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) /* yay! */ return FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT); + _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL; + int mount_id = -1, mount_id_parent = -1; + bool nosupp = false; + r = name_to_handle_at_try_fid(fd, filename, &h, &mount_id, flags); if (r < 0) { if (is_name_to_handle_at_fatal_error(r)) @@ -281,13 +289,12 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { if (!ERRNO_IS_NOT_SUPPORTED(r)) goto fallback_fdinfo; - /* This kernel or file system does not support name_to_handle_at(), hence let's see - * if the upper fs supports it (in which case it is a mount point), otherwise fall - * back to the traditional stat() logic */ + /* This file system does not support name_to_handle_at(), hence let's see if the upper fs + * supports it (in which case it is a mount point), otherwise fall back to the fdinfo logic. */ nosupp = true; } - if (isempty(filename)) + if (fd_is_self) r = name_to_handle_at_try_fid(fd, "..", &h_parent, &mount_id_parent, 0); /* can't work for non-directories 😢 */ else r = name_to_handle_at_try_fid(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH); @@ -319,12 +326,10 @@ 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 (ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_PRIVILEGE(r)) - goto fallback_fstat; if (r < 0) return r; - if (isempty(filename)) + if (fd_is_self) r = fd_fdinfo_mnt_id(fd, "..", 0, &mount_id_parent); /* can't work for non-directories 😢 */ else r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); @@ -336,38 +341,33 @@ fallback_fdinfo: /* Hmm, so, the mount ids are the same. This leaves one special case though for the root file * system. For that, let's see if the parent directory has the same inode as we are interested - * in. Hence, let's also do fstat() checks now, too, but avoid the st_dev comparisons, since they - * aren't that useful on unionfs mounts. */ - check_st_dev = false; + * in. */ + + struct stat a, b; -fallback_fstat: /* yay for fstatat() taking a different set of flags than the other _at() above */ - if (flags & AT_SYMLINK_FOLLOW) - flags &= ~AT_SYMLINK_FOLLOW; - else - flags |= AT_SYMLINK_NOFOLLOW; - if (fstatat(fd, filename, &a, flags) < 0) + if (fstatat(fd, filename, &a, at_flags_normalize_nofollow(flags)) < 0) return -errno; - if (isempty(filename)) + if (fd_is_self) r = fstatat(fd, "..", &b, 0); else r = fstatat(fd, "", &b, AT_EMPTY_PATH); if (r < 0) return -errno; - /* A directory with same device and inode as its parent? Must be the root directory */ - if (stat_inode_same(&a, &b)) - return 1; - - return check_st_dev && (a.st_dev != b.st_dev); + /* A directory with same device and inode as its parent must be the root directory. Otherwise + * not a mount point. + * + * NB: we avoid inode_same_at() here because it internally attempts name_to_handle_at_try_fid() first, + * which is redundant. */ + return stat_inode_same(&a, &b); } /* flags can be AT_SYMLINK_FOLLOW or 0 */ int path_is_mount_point_full(const char *path, const char *root, int flags) { - _cleanup_free_ char *canonical = NULL; - _cleanup_close_ int fd = -EBADF; - int r; + _cleanup_close_ int dfd = -EBADF; + _cleanup_free_ char *fn = NULL; assert(path); assert((flags & ~AT_SYMLINK_FOLLOW) == 0); @@ -375,22 +375,16 @@ int path_is_mount_point_full(const char *path, const char *root, int flags) { if (path_equal(path, "/")) return 1; - /* we need to resolve symlinks manually, we can't just rely on fd_is_mount_point() to do that for us; + /* we need to resolve symlinks manually, we can't just rely on is_mount_point_at() to do that for us; * if we have a structure like /bin -> /usr/bin/ and /usr is a mount point, then the parent that we * look at needs to be /usr, not /. */ - if (FLAGS_SET(flags, AT_SYMLINK_FOLLOW)) { - r = chase(path, root, CHASE_TRAIL_SLASH, &canonical, NULL); - if (r < 0) - return r; + dfd = chase_and_open_parent(path, root, + CHASE_TRAIL_SLASH|(FLAGS_SET(flags, AT_SYMLINK_FOLLOW) ? 0 : CHASE_NOFOLLOW), + &fn); + if (dfd < 0) + return dfd; - path = canonical; - } - - fd = open_parent(path, O_PATH|O_CLOEXEC, 0); - if (fd < 0) - return fd; - - return fd_is_mount_point(fd, last_path_component(path), flags); + return is_mount_point_at(dfd, fn, flags); } int path_get_mnt_id_at_fallback(int dir_fd, const char *path, int *ret) { @@ -400,7 +394,7 @@ int path_get_mnt_id_at_fallback(int dir_fd, const char *path, int *ret) { assert(ret); r = name_to_handle_at_loop(dir_fd, path, NULL, ret, isempty(path) ? AT_EMPTY_PATH : 0); - if (r == 0 || is_name_to_handle_at_fatal_error(r)) + if (r >= 0 || is_name_to_handle_at_fatal_error(r)) return r; return fd_fdinfo_mnt_id(dir_fd, path, isempty(path) ? AT_EMPTY_PATH : 0, ret); diff --git a/src/basic/mountpoint-util.h b/src/basic/mountpoint-util.h index f506e01a41..43e4758143 100644 --- a/src/basic/mountpoint-util.h +++ b/src/basic/mountpoint-util.h @@ -49,7 +49,7 @@ static inline int path_get_mnt_id(const char *path, int *ret) { return path_get_mnt_id_at(AT_FDCWD, path, ret); } -int fd_is_mount_point(int fd, const char *filename, int flags); +int is_mount_point_at(int fd, const char *filename, int flags); int path_is_mount_point_full(const char *path, const char *root, int flags); static inline int path_is_mount_point(const char *path) { return path_is_mount_point_full(path, NULL, 0); diff --git a/src/basic/recurse-dir.c b/src/basic/recurse-dir.c index 389a784c40..3d6061cfc0 100644 --- a/src/basic/recurse-dir.c +++ b/src/basic/recurse-dir.c @@ -384,7 +384,7 @@ int recurse_dir( if (sx_valid && FLAGS_SET(sx.stx_attributes_mask, STATX_ATTR_MOUNT_ROOT)) is_mount = FLAGS_SET(sx.stx_attributes, STATX_ATTR_MOUNT_ROOT); else { - r = fd_is_mount_point(dir_fd, de->entries[i]->d_name, 0); + r = is_mount_point_at(dir_fd, de->entries[i]->d_name, 0); if (r < 0) log_debug_errno(r, "Failed to determine whether %s is a submount, assuming not: %m", p); diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 33e651c6c1..956cac6708 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -1762,7 +1762,7 @@ static int action_umount(const char *path) { if (fd < 0) return log_error_errno(fd, "Failed to resolve path '%s': %m", path); - r = fd_is_mount_point(fd, NULL, 0); + r = is_mount_point_at(fd, NULL, 0); if (r == 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "'%s' is not a mount point", canonical); if (r < 0) diff --git a/src/shared/copy.c b/src/shared/copy.c index bca41cf122..cb3944b279 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -1147,7 +1147,7 @@ static int fd_copy_directory( if (buf.st_dev != original_device) continue; - r = fd_is_mount_point(dirfd(d), de->d_name, 0); + r = is_mount_point_at(dirfd(d), de->d_name, 0); if (r < 0) return r; if (r > 0) diff --git a/src/shared/machine-id-setup.c b/src/shared/machine-id-setup.c index bc4d890d35..83f609c43f 100644 --- a/src/shared/machine-id-setup.c +++ b/src/shared/machine-id-setup.c @@ -329,7 +329,7 @@ int machine_id_commit(const char *root) { if (!etc_machine_id) return log_oom(); - r = fd_is_mount_point(etc_fd, "machine-id", /* flags= */ 0); + r = is_mount_point_at(etc_fd, "machine-id", /* flags= */ 0); if (r < 0) return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", etc_machine_id); if (r == 0) { diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index a9ce8d7e5a..c7a9984528 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -1346,7 +1346,7 @@ int fd_make_mount_point(int fd) { assert(fd >= 0); - r = fd_is_mount_point(fd, NULL, 0); + r = is_mount_point_at(fd, NULL, 0); if (r < 0) return log_debug_errno(r, "Failed to determine whether file descriptor is a mount point: %m"); if (r > 0) diff --git a/src/shared/pcrextend-util.c b/src/shared/pcrextend-util.c index 5ec9a069b7..96c1c07bc8 100644 --- a/src/shared/pcrextend-util.c +++ b/src/shared/pcrextend-util.c @@ -97,7 +97,7 @@ int pcrextend_file_system_word(const char *path, char **ret_word, char **ret_nor if (dfd < 0) return log_error_errno(dfd, "Failed to open path '%s': %m", path); - r = fd_is_mount_point(dfd, NULL, 0); + r = is_mount_point_at(dfd, NULL, 0); if (r < 0) return log_error_errno(r, "Failed to determine if path '%s' is mount point: %m", normalized_path); if (r == 0) diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c index 767db48cc0..2f50fa30ea 100644 --- a/src/shared/rm-rf.c +++ b/src/shared/rm-rf.c @@ -219,7 +219,7 @@ static int rm_rf_inner_child( return 0; /* Stop at mount points */ - r = fd_is_mount_point(fd, fname, 0); + r = is_mount_point_at(fd, fname, 0); if (r < 0) return r; if (r > 0) diff --git a/src/test/test-mount-util.c b/src/test/test-mount-util.c index 0d7e803b54..352c5a1af6 100644 --- a/src/test/test-mount-util.c +++ b/src/test/test-mount-util.c @@ -452,14 +452,14 @@ TEST(fd_make_mount_point) { fd = open(s, O_PATH|O_CLOEXEC); assert_se(fd >= 0); - assert_se(fd_is_mount_point(fd, NULL, AT_SYMLINK_FOLLOW) == 0); + assert_se(is_mount_point_at(fd, NULL, AT_SYMLINK_FOLLOW) == 0); assert_se(fd_make_mount_point(fd) > 0); /* Reopen the inode so that we end up on the new mount */ fd2 = open(s, O_PATH|O_CLOEXEC); - assert_se(fd_is_mount_point(fd2, NULL, AT_SYMLINK_FOLLOW) > 0); + assert_se(is_mount_point_at(fd2, NULL, AT_SYMLINK_FOLLOW) > 0); assert_se(fd_make_mount_point(fd2) == 0); diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c index 89093d0212..c712cd8f2b 100644 --- a/src/test/test-mountpoint-util.c +++ b/src/test/test-mountpoint-util.c @@ -271,8 +271,9 @@ TEST(path_is_mount_point) { assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0); } -TEST(fd_is_mount_point) { +TEST(is_mount_point_at) { _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL; + _cleanup_free_ char *pwd = NULL; _cleanup_close_ int fd = -EBADF; int r; @@ -280,44 +281,51 @@ TEST(fd_is_mount_point) { assert_se(fd >= 0); /* Not allowed, since "/" is a path, not a plain filename */ - assert_se(fd_is_mount_point(fd, "/", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, ".", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, "./", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, "..", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, "../", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, "", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, "/proc", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, "/proc/", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, "proc/sys", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, "proc/sys/", 0) == -EINVAL); + assert_se(is_mount_point_at(fd, "/", 0) == -EINVAL); + assert_se(is_mount_point_at(fd, "..", 0) == -EINVAL); + assert_se(is_mount_point_at(fd, "../", 0) == -EINVAL); + assert_se(is_mount_point_at(fd, "/proc", 0) == -EINVAL); + assert_se(is_mount_point_at(fd, "/proc/", 0) == -EINVAL); + assert_se(is_mount_point_at(fd, "proc/sys", 0) == -EINVAL); + assert_se(is_mount_point_at(fd, "proc/sys/", 0) == -EINVAL); /* This one definitely is a mount point */ - assert_se(fd_is_mount_point(fd, "proc", 0) > 0); - assert_se(fd_is_mount_point(fd, "proc/", 0) > 0); + assert_se(is_mount_point_at(fd, "proc", 0) > 0); + assert_se(is_mount_point_at(fd, "proc/", 0) > 0); safe_close(fd); fd = open("/tmp", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY); assert_se(fd >= 0); assert_se(mkdtemp_malloc("/tmp/not-mounted-XXXXXX", &tmpdir) >= 0); - assert_se(fd_is_mount_point(fd, basename(tmpdir), 0) == 0); - assert_se(fd_is_mount_point(fd, strjoina(basename(tmpdir), "/"), 0) == 0); + assert_se(is_mount_point_at(fd, basename(tmpdir), 0) == 0); + assert_se(is_mount_point_at(fd, strjoina(basename(tmpdir), "/"), 0) == 0); safe_close(fd); fd = open("/proc", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY); assert_se(fd >= 0); - assert_se(fd_is_mount_point(fd, NULL, 0) > 0); - assert_se(fd_is_mount_point(fd, "", 0) == -EINVAL); - assert_se(fd_is_mount_point(fd, "version", 0) == 0); + ASSERT_OK_POSITIVE(is_mount_point_at(fd, NULL, 0)); + ASSERT_OK_POSITIVE(is_mount_point_at(fd, "", 0)); + ASSERT_OK_POSITIVE(is_mount_point_at(fd, ".", 0)); + ASSERT_OK_POSITIVE(is_mount_point_at(fd, "./", 0)); + ASSERT_OK_ZERO(is_mount_point_at(fd, "version", 0)); + + ASSERT_OK(safe_getcwd(&pwd)); + ASSERT_OK_ERRNO(fchdir(fd)); + + ASSERT_OK_POSITIVE(is_mount_point_at(AT_FDCWD, NULL, 0)); + ASSERT_OK_POSITIVE(is_mount_point_at(AT_FDCWD, "", 0)); + ASSERT_OK_POSITIVE(is_mount_point_at(AT_FDCWD, "./", 0)); + + ASSERT_OK_ERRNO(chdir(pwd)); safe_close(fd); fd = open("/proc/version", O_RDONLY|O_CLOEXEC|O_NOCTTY); assert_se(fd >= 0); - r = fd_is_mount_point(fd, NULL, 0); + r = is_mount_point_at(fd, NULL, 0); assert_se(IN_SET(r, 0, -ENOTDIR)); /* on old kernels we can't determine if regular files are mount points if we have no directory fd */ - assert_se(fd_is_mount_point(fd, "", 0) == -EINVAL); if (!mount_new_api_supported()) return; @@ -346,7 +354,7 @@ TEST(fd_is_mount_point) { ASSERT_OK(readlinkat_malloc(fd, "regular", &t)); ASSERT_STREQ(t, "/usr"); - ASSERT_OK(fd_is_mount_point(fd, "regular", 0)); + ASSERT_OK(is_mount_point_at(fd, "regular", 0)); } TEST(ms_nosymfollow_supported) { diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index f3cbaf48a2..6ce4a78adc 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -744,7 +744,7 @@ static int dir_cleanup( if (S_ISDIR(sx.stx_mode)) { int q; - q = fd_is_mount_point(dirfd(d), de->d_name, 0); + q = is_mount_point_at(dirfd(d), de->d_name, 0); if (q < 0) log_debug_errno(q, "Failed to determine whether \"%s/%s\" is a mount point, ignoring: %m", p, de->d_name); else if (q > 0) { @@ -2687,7 +2687,7 @@ static int rm_if_wrong_type_safe( } /* Do not remove mount points. */ - r = fd_is_mount_point(parent_fd, name, follow_links ? AT_SYMLINK_FOLLOW : 0); + r = is_mount_point_at(parent_fd, name, follow_links ? AT_SYMLINK_FOLLOW : 0); if (r < 0) (void) log_warning_errno(r, "Failed to check if \"%s/%s\" is a mount point: %m; continuing.", parent_name ?: "...", name);