]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Split out part of mount-util.c into mountpoint-util.c
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 29 Nov 2018 09:24:39 +0000 (10:24 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 29 Nov 2018 20:03:44 +0000 (21:03 +0100)
The idea is that anything which is related to actually manipulating mounts is
in mount-util.c, but functions for mountpoint introspection are moved to the
new file. Anything which requires libmount must be in mount-util.c.

This was supposed to be a preparation for further changes, with no functional
difference, but it results in a significant change in linkage:

$ ldd build/libnss_*.so.2
(before)
build/libnss_myhostname.so.2:
linux-vdso.so.1 (0x00007fff77bf5000)
librt.so.1 => /lib64/librt.so.1 (0x00007f4bbb7b2000)
libmount.so.1 => /lib64/libmount.so.1 (0x00007f4bbb755000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f4bbb734000)
libc.so.6 => /lib64/libc.so.6 (0x00007f4bbb56e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4bbb8c1000)
libblkid.so.1 => /lib64/libblkid.so.1 (0x00007f4bbb51b000)
libuuid.so.1 => /lib64/libuuid.so.1 (0x00007f4bbb512000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f4bbb4e3000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007f4bbb45e000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f4bbb458000)
build/libnss_mymachines.so.2:
linux-vdso.so.1 (0x00007ffc19cc0000)
librt.so.1 => /lib64/librt.so.1 (0x00007fdecb74b000)
libcap.so.2 => /lib64/libcap.so.2 (0x00007fdecb744000)
libmount.so.1 => /lib64/libmount.so.1 (0x00007fdecb6e7000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fdecb6c6000)
libc.so.6 => /lib64/libc.so.6 (0x00007fdecb500000)
/lib64/ld-linux-x86-64.so.2 (0x00007fdecb8a9000)
libblkid.so.1 => /lib64/libblkid.so.1 (0x00007fdecb4ad000)
libuuid.so.1 => /lib64/libuuid.so.1 (0x00007fdecb4a2000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fdecb475000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007fdecb3f0000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fdecb3ea000)
build/libnss_resolve.so.2:
linux-vdso.so.1 (0x00007ffe8ef8e000)
librt.so.1 => /lib64/librt.so.1 (0x00007fcf314bd000)
libcap.so.2 => /lib64/libcap.so.2 (0x00007fcf314b6000)
libmount.so.1 => /lib64/libmount.so.1 (0x00007fcf31459000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fcf31438000)
libc.so.6 => /lib64/libc.so.6 (0x00007fcf31272000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcf31615000)
libblkid.so.1 => /lib64/libblkid.so.1 (0x00007fcf3121f000)
libuuid.so.1 => /lib64/libuuid.so.1 (0x00007fcf31214000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fcf311e7000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007fcf31162000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fcf3115c000)
build/libnss_systemd.so.2:
linux-vdso.so.1 (0x00007ffda6d17000)
librt.so.1 => /lib64/librt.so.1 (0x00007f610b83c000)
libcap.so.2 => /lib64/libcap.so.2 (0x00007f610b835000)
libmount.so.1 => /lib64/libmount.so.1 (0x00007f610b7d8000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f610b7b7000)
libc.so.6 => /lib64/libc.so.6 (0x00007f610b5f1000)
/lib64/ld-linux-x86-64.so.2 (0x00007f610b995000)
libblkid.so.1 => /lib64/libblkid.so.1 (0x00007f610b59e000)
libuuid.so.1 => /lib64/libuuid.so.1 (0x00007f610b593000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f610b566000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007f610b4e1000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007f610b4db000)

(after)
build/libnss_myhostname.so.2:
linux-vdso.so.1 (0x00007fff0b5e2000)
librt.so.1 => /lib64/librt.so.1 (0x00007fde0c328000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fde0c307000)
libc.so.6 => /lib64/libc.so.6 (0x00007fde0c141000)
/lib64/ld-linux-x86-64.so.2 (0x00007fde0c435000)
build/libnss_mymachines.so.2:
linux-vdso.so.1 (0x00007ffdc30a7000)
librt.so.1 => /lib64/librt.so.1 (0x00007f06ecabb000)
libcap.so.2 => /lib64/libcap.so.2 (0x00007f06ecab4000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f06eca93000)
libc.so.6 => /lib64/libc.so.6 (0x00007f06ec8cd000)
/lib64/ld-linux-x86-64.so.2 (0x00007f06ecc15000)
build/libnss_resolve.so.2:
linux-vdso.so.1 (0x00007ffe95747000)
librt.so.1 => /lib64/librt.so.1 (0x00007fa56a80f000)
libcap.so.2 => /lib64/libcap.so.2 (0x00007fa56a808000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fa56a7e7000)
libc.so.6 => /lib64/libc.so.6 (0x00007fa56a621000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa56a964000)
build/libnss_systemd.so.2:
linux-vdso.so.1 (0x00007ffe67b51000)
librt.so.1 => /lib64/librt.so.1 (0x00007ffb32113000)
libcap.so.2 => /lib64/libcap.so.2 (0x00007ffb3210c000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007ffb320eb000)
libc.so.6 => /lib64/libc.so.6 (0x00007ffb31f25000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffb3226a000)

I don't quite understand what is going on here, but let's not be too picky.

36 files changed:
src/basic/copy.c
src/basic/meson.build
src/basic/mount-util.c
src/basic/mount-util.h
src/basic/mountpoint-util.c [new file with mode: 0644]
src/basic/mountpoint-util.h [new file with mode: 0644]
src/basic/rm-rf.c
src/core/automount.c
src/core/dbus-execute.c
src/core/load-fragment.c
src/core/machine-id-setup.c
src/core/mount-setup.c
src/core/mount.c
src/core/namespace.c
src/core/umount.c
src/fstab-generator/fstab-generator.c
src/gpt-auto-generator/gpt-auto-generator.c
src/libsystemd/sd-device/device-monitor.c
src/login/user-runtime-dir.c
src/mount/mount-tool.c
src/nspawn/nspawn-cgroup.c
src/nspawn/nspawn-mount.c
src/nspawn/nspawn.c
src/partition/growfs.c
src/shared/bus-unit-util.c
src/shared/bus-util.c
src/shared/condition.c
src/shared/dissect-image.c
src/shared/switch-root.c
src/test/meson.build
src/test/test-mount-util.c
src/test/test-mountpoint-util.c [new file with mode: 0644]
src/test/test-path-util.c
src/test/test-stat-util.c
src/tmpfiles/tmpfiles.c
src/volatile-root/volatile-root.c

index 7a4db459e3bb4bddd911753dc910cf1072f9f119..50240de8b6e280627c74d2fc3796ce3143a5fa63 100644 (file)
@@ -24,7 +24,7 @@
 #include "io-util.h"
 #include "macro.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
index b13897f334a902de6ae2bca3a1513fbce2d773d8..906d1c1b3d61474dda8de80f4edffc430b32a107 100644 (file)
@@ -96,6 +96,8 @@ basic_sources = files('''
         mkdir.h
         mount-util.c
         mount-util.h
+        mountpoint-util.c
+        mountpoint-util.h
         nss-util.h
         ordered-set.c
         ordered-set.h
index ec607c7360a03e698d04f8334b0b5b4864f73ad1..9fa995f69355746bd0babeefca89992eac2c0880 100644 (file)
@@ -20,6 +20,7 @@
 #include "fs-util.h"
 #include "hashmap.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "set.h"
 #include "string-util.h"
 #include "strv.h"
 
-/* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of
- * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code
- * is recompiled then it would cease working on old kernels, as those refuse any sizes larger than this value with
- * EINVAL right-away. Hence, let's disconnect ourselves from any such API changes, and stick to the original definition
- * from when it was introduced. We use it as a start value only anyway (see below), and hence should be able to deal
- * with large file handles anyway. */
-#define ORIGINAL_MAX_HANDLE_SZ 128
-
-int name_to_handle_at_loop(
-                int fd,
-                const char *path,
-                struct file_handle **ret_handle,
-                int *ret_mnt_id,
-                int flags) {
-
-        _cleanup_free_ struct file_handle *h = NULL;
-        size_t n = ORIGINAL_MAX_HANDLE_SZ;
-
-        /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified
-         * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a
-         * start value, it is not an upper bound on the buffer size required.
-         *
-         * This improves on raw name_to_handle_at() also in one other regard: ret_handle and ret_mnt_id can be passed
-         * as NULL if there's no interest in either. */
-
-        for (;;) {
-                int mnt_id = -1;
-
-                h = malloc0(offsetof(struct file_handle, f_handle) + n);
-                if (!h)
-                        return -ENOMEM;
-
-                h->handle_bytes = n;
-
-                if (name_to_handle_at(fd, path, h, &mnt_id, flags) >= 0) {
-
-                        if (ret_handle)
-                                *ret_handle = TAKE_PTR(h);
-
-                        if (ret_mnt_id)
-                                *ret_mnt_id = mnt_id;
-
-                        return 0;
-                }
-                if (errno != EOVERFLOW)
-                        return -errno;
-
-                if (!ret_handle && ret_mnt_id && mnt_id >= 0) {
-
-                        /* As it appears, name_to_handle_at() fills in mnt_id even when it returns EOVERFLOW when the
-                         * buffer is too small, but that's undocumented. Hence, let's make use of this if it appears to
-                         * be filled in, and the caller was interested in only the mount ID an nothing else. */
-
-                        *ret_mnt_id = mnt_id;
-                        return 0;
-                }
-
-                /* If name_to_handle_at() didn't increase the byte size, then this EOVERFLOW is caused by something
-                 * else (apparently EOVERFLOW is returned for untriggered nfs4 mounts sometimes), not by the too small
-                 * buffer. In that case propagate EOVERFLOW */
-                if (h->handle_bytes <= n)
-                        return -EOVERFLOW;
-
-                /* The buffer was too small. Size the new buffer by what name_to_handle_at() returned. */
-                n = h->handle_bytes;
-                if (offsetof(struct file_handle, f_handle) + n < n) /* check for addition overflow */
-                        return -EOVERFLOW;
-
-                h = mfree(h);
-        }
-}
-
-static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
-        char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
-        _cleanup_free_ char *fdinfo = NULL;
-        _cleanup_close_ int subfd = -1;
-        char *p;
-        int r;
-
-        if ((flags & AT_EMPTY_PATH) && isempty(filename))
-                xsprintf(path, "/proc/self/fdinfo/%i", fd);
-        else {
-                subfd = openat(fd, filename, O_CLOEXEC|O_PATH);
-                if (subfd < 0)
-                        return -errno;
-
-                xsprintf(path, "/proc/self/fdinfo/%i", subfd);
-        }
-
-        r = read_full_file(path, &fdinfo, NULL);
-        if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
-                return -EOPNOTSUPP;
-        if (r < 0)
-                return r;
-
-        p = startswith(fdinfo, "mnt_id:");
-        if (!p) {
-                p = strstr(fdinfo, "\nmnt_id:");
-                if (!p) /* The mnt_id field is a relatively new addition */
-                        return -EOPNOTSUPP;
-
-                p += 8;
-        }
-
-        p += strspn(p, WHITESPACE);
-        p[strcspn(p, WHITESPACE)] = 0;
-
-        return safe_atoi(p, mnt_id);
-}
-
-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 stat a, b;
-        int r;
-
-        assert(fd >= 0);
-        assert(filename);
-
-        /* First we will try the name_to_handle_at() syscall, which
-         * tells us the mount id and an opaque file "handle". It is
-         * not supported everywhere though (kernel compile-time
-         * option, not all file systems are hooked up). If it works
-         * the mount id is usually good enough to tell us whether
-         * something is a mount point.
-         *
-         * If that didn't work we will try to read the mount id from
-         * /proc/self/fdinfo/<fd>. 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.
-         *
-         * 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. */
-
-        r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
-        if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
-                /* This 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 nfs4), or some general name_to_handle_at() flakiness
-                 * (EINVAL): fall back to simpler logic. */
-                goto fallback_fdinfo;
-        else if (r == -EOPNOTSUPP)
-                /* 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 fallback to the traditional stat()
-                 * logic */
-                nosupp = true;
-        else if (r < 0)
-                return r;
-
-        r = name_to_handle_at_loop(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH);
-        if (r == -EOPNOTSUPP) {
-                if (nosupp)
-                        /* Neither parent nor child do name_to_handle_at()?  We have no choice but to fall back. */
-                        goto fallback_fdinfo;
-                else
-                        /* The parent can't do name_to_handle_at() but the directory we are interested in can?  If so,
-                         * it must be a mount point. */
-                        return 1;
-        } else if (r < 0)
-                return r;
-
-        /* The parent can do name_to_handle_at() but the
-         * directory we are interested in can't? If so, it
-         * must be a mount point. */
-        if (nosupp)
-                return 1;
-
-        /* If the file handle for the directory we are
-         * interested in and its parent are identical, we
-         * assume this is the root directory, which is a mount
-         * point. */
-
-        if (h->handle_bytes == h_parent->handle_bytes &&
-            h->handle_type == h_parent->handle_type &&
-            memcmp(h->f_handle, h_parent->f_handle, h->handle_bytes) == 0)
-                return 1;
-
-        return mount_id != mount_id_parent;
-
-fallback_fdinfo:
-        r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
-        if (IN_SET(r, -EOPNOTSUPP, -EACCES, -EPERM))
-                goto fallback_fstat;
-        if (r < 0)
-                return r;
-
-        r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
-        if (r < 0)
-                return r;
-
-        if (mount_id != mount_id_parent)
-                return 1;
-
-        /* 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;
-
-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)
-                return -errno;
-
-        if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
-                return -errno;
-
-        /* A directory with same device and inode as its parent? Must
-         * be the root directory */
-        if (a.st_dev == b.st_dev &&
-            a.st_ino == b.st_ino)
-                return 1;
-
-        return check_st_dev && (a.st_dev != b.st_dev);
-}
-
-/* flags can be AT_SYMLINK_FOLLOW or 0 */
-int path_is_mount_point(const char *t, const char *root, int flags) {
-        _cleanup_free_ char *canonical = NULL;
-        _cleanup_close_ int fd = -1;
-        int r;
-
-        assert(t);
-        assert((flags & ~AT_SYMLINK_FOLLOW) == 0);
-
-        if (path_equal(t, "/"))
-                return 1;
-
-        /* we need to resolve symlinks manually, we can't just rely on
-         * fd_is_mount_point() 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 & AT_SYMLINK_FOLLOW) {
-                r = chase_symlinks(t, root, CHASE_TRAIL_SLASH, &canonical);
-                if (r < 0)
-                        return r;
-
-                t = canonical;
-        }
-
-        fd = open_parent(t, O_PATH|O_CLOEXEC, 0);
-        if (fd < 0)
-                return -errno;
-
-        return fd_is_mount_point(fd, last_path_component(t), flags);
-}
-
-int path_get_mnt_id(const char *path, int *ret) {
-        int r;
-
-        r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0);
-        if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) /* kernel/fs don't support this, or seccomp blocks access, or untriggered mount, or name_to_handle_at() is flaky */
-                return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);
-
-        return r;
-}
-
 int umount_recursive(const char *prefix, int flags) {
         bool again;
         int n = 0, r;
@@ -601,86 +329,6 @@ int mount_move_root(const char *path) {
         return 0;
 }
 
-bool fstype_is_network(const char *fstype) {
-        const char *x;
-
-        x = startswith(fstype, "fuse.");
-        if (x)
-                fstype = x;
-
-        return STR_IN_SET(fstype,
-                          "afs",
-                          "cifs",
-                          "smbfs",
-                          "sshfs",
-                          "ncpfs",
-                          "ncp",
-                          "nfs",
-                          "nfs4",
-                          "gfs",
-                          "gfs2",
-                          "glusterfs",
-                          "pvfs2", /* OrangeFS */
-                          "ocfs2",
-                          "lustre");
-}
-
-bool fstype_is_api_vfs(const char *fstype) {
-        return STR_IN_SET(fstype,
-                          "autofs",
-                          "bpf",
-                          "cgroup",
-                          "cgroup2",
-                          "configfs",
-                          "cpuset",
-                          "debugfs",
-                          "devpts",
-                          "devtmpfs",
-                          "efivarfs",
-                          "fusectl",
-                          "hugetlbfs",
-                          "mqueue",
-                          "proc",
-                          "pstore",
-                          "ramfs",
-                          "securityfs",
-                          "sysfs",
-                          "tmpfs",
-                          "tracefs");
-}
-
-bool fstype_is_ro(const char *fstype) {
-        /* All Linux file systems that are necessarily read-only */
-        return STR_IN_SET(fstype,
-                          "DM_verity_hash",
-                          "iso9660",
-                          "squashfs");
-}
-
-bool fstype_can_discard(const char *fstype) {
-        return STR_IN_SET(fstype,
-                          "btrfs",
-                          "ext4",
-                          "vfat",
-                          "xfs");
-}
-
-bool fstype_can_uid_gid(const char *fstype) {
-
-        /* All file systems that have a uid=/gid= mount option that fixates the owners of all files and directories,
-         * current and future. */
-
-        return STR_IN_SET(fstype,
-                          "adfs",
-                          "fat",
-                          "hfs",
-                          "hpfs",
-                          "iso9660",
-                          "msdos",
-                          "ntfs",
-                          "vfat");
-}
-
 int repeat_unmount(const char *path, int flags) {
         bool done = false;
 
@@ -852,37 +500,6 @@ int umount_verbose(const char *what) {
         return 0;
 }
 
-const char *mount_propagation_flags_to_string(unsigned long flags) {
-
-        switch (flags & (MS_SHARED|MS_SLAVE|MS_PRIVATE)) {
-        case 0:
-                return "";
-        case MS_SHARED:
-                return "shared";
-        case MS_SLAVE:
-                return "slave";
-        case MS_PRIVATE:
-                return "private";
-        }
-
-        return NULL;
-}
-
-int mount_propagation_flags_from_string(const char *name, unsigned long *ret) {
-
-        if (isempty(name))
-                *ret = 0;
-        else if (streq(name, "shared"))
-                *ret = MS_SHARED;
-        else if (streq(name, "slave"))
-                *ret = MS_SLAVE;
-        else if (streq(name, "private"))
-                *ret = MS_PRIVATE;
-        else
-                return -EINVAL;
-        return 0;
-}
-
 int mount_option_mangle(
                 const char *options,
                 unsigned long mount_flags,
@@ -951,46 +568,3 @@ int mount_option_mangle(
 
         return 0;
 }
-
-int dev_is_devtmpfs(void) {
-        _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
-        int mount_id, r;
-        char *e;
-
-        r = path_get_mnt_id("/dev", &mount_id);
-        if (r < 0)
-                return r;
-
-        proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
-        if (!proc_self_mountinfo)
-                return -errno;
-
-        (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER);
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL;
-                int mid;
-
-                r = read_line(proc_self_mountinfo, LONG_LINE_MAX, &line);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                if (sscanf(line, "%i", &mid) != 1)
-                        continue;
-
-                if (mid != mount_id)
-                        continue;
-
-                e = strstr(line, " - ");
-                if (!e)
-                        continue;
-
-                /* accept any name that starts with the currently expected type */
-                if (startswith(e + 3, "devtmpfs"))
-                        return true;
-        }
-
-        return false;
-}
index ad8c47cb325f89b97ecbc3b08dbe31b557d2754b..00df1b0e55e656742842c218c0ca5c43ae393da9 100644 (file)
@@ -1,25 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include <fcntl.h>
 #include <mntent.h>
-#include <stdbool.h>
 #include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
 
 #include "macro.h"
-#include "missing.h"
-
-int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags);
-
-int path_get_mnt_id(const char *path, int *ret);
-
-int fd_is_mount_point(int fd, const char *filename, int flags);
-int path_is_mount_point(const char *path, const char *root, int flags);
 
 int repeat_unmount(const char *path, int flags);
-
 int umount_recursive(const char *target, int flags);
 int bind_remount_recursive(const char *prefix, bool ro, char **blacklist);
 int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **blacklist, FILE *proc_self_mountinfo);
@@ -29,14 +16,6 @@ int mount_move_root(const char *path);
 DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
 #define _cleanup_endmntent_ _cleanup_(endmntentp)
 
-bool fstype_is_network(const char *fstype);
-bool fstype_is_api_vfs(const char *fstype);
-bool fstype_is_ro(const char *fsype);
-bool fstype_can_discard(const char *fstype);
-bool fstype_can_uid_gid(const char *fstype);
-
-const char* mode_to_inaccessible_node(mode_t mode);
-
 int mount_verbose(
                 int error_log_level,
                 const char *what,
@@ -46,13 +25,10 @@ int mount_verbose(
                 const char *options);
 int umount_verbose(const char *where);
 
-const char *mount_propagation_flags_to_string(unsigned long flags);
-int mount_propagation_flags_from_string(const char *name, unsigned long *ret);
-
 int mount_option_mangle(
                 const char *options,
                 unsigned long mount_flags,
                 unsigned long *ret_mount_flags,
                 char **ret_remaining_options);
 
-int dev_is_devtmpfs(void);
+const char* mode_to_inaccessible_node(mode_t mode);
diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c
new file mode 100644 (file)
index 0000000..0a9f479
--- /dev/null
@@ -0,0 +1,444 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio_ext.h>
+#include <sys/mount.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "missing.h"
+#include "mountpoint-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "stdio-util.h"
+#include "strv.h"
+
+/* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of
+ * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code
+ * is recompiled then it would cease working on old kernels, as those refuse any sizes larger than this value with
+ * EINVAL right-away. Hence, let's disconnect ourselves from any such API changes, and stick to the original definition
+ * from when it was introduced. We use it as a start value only anyway (see below), and hence should be able to deal
+ * with large file handles anyway. */
+#define ORIGINAL_MAX_HANDLE_SZ 128
+
+int name_to_handle_at_loop(
+                int fd,
+                const char *path,
+                struct file_handle **ret_handle,
+                int *ret_mnt_id,
+                int flags) {
+
+        _cleanup_free_ struct file_handle *h = NULL;
+        size_t n = ORIGINAL_MAX_HANDLE_SZ;
+
+        /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified
+         * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a
+         * start value, it is not an upper bound on the buffer size required.
+         *
+         * This improves on raw name_to_handle_at() also in one other regard: ret_handle and ret_mnt_id can be passed
+         * as NULL if there's no interest in either. */
+
+        for (;;) {
+                int mnt_id = -1;
+
+                h = malloc0(offsetof(struct file_handle, f_handle) + n);
+                if (!h)
+                        return -ENOMEM;
+
+                h->handle_bytes = n;
+
+                if (name_to_handle_at(fd, path, h, &mnt_id, flags) >= 0) {
+
+                        if (ret_handle)
+                                *ret_handle = TAKE_PTR(h);
+
+                        if (ret_mnt_id)
+                                *ret_mnt_id = mnt_id;
+
+                        return 0;
+                }
+                if (errno != EOVERFLOW)
+                        return -errno;
+
+                if (!ret_handle && ret_mnt_id && mnt_id >= 0) {
+
+                        /* As it appears, name_to_handle_at() fills in mnt_id even when it returns EOVERFLOW when the
+                         * buffer is too small, but that's undocumented. Hence, let's make use of this if it appears to
+                         * be filled in, and the caller was interested in only the mount ID an nothing else. */
+
+                        *ret_mnt_id = mnt_id;
+                        return 0;
+                }
+
+                /* If name_to_handle_at() didn't increase the byte size, then this EOVERFLOW is caused by something
+                 * else (apparently EOVERFLOW is returned for untriggered nfs4 mounts sometimes), not by the too small
+                 * buffer. In that case propagate EOVERFLOW */
+                if (h->handle_bytes <= n)
+                        return -EOVERFLOW;
+
+                /* The buffer was too small. Size the new buffer by what name_to_handle_at() returned. */
+                n = h->handle_bytes;
+                if (offsetof(struct file_handle, f_handle) + n < n) /* check for addition overflow */
+                        return -EOVERFLOW;
+
+                h = mfree(h);
+        }
+}
+
+static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
+        char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
+        _cleanup_free_ char *fdinfo = NULL;
+        _cleanup_close_ int subfd = -1;
+        char *p;
+        int r;
+
+        if ((flags & AT_EMPTY_PATH) && isempty(filename))
+                xsprintf(path, "/proc/self/fdinfo/%i", fd);
+        else {
+                subfd = openat(fd, filename, O_CLOEXEC|O_PATH);
+                if (subfd < 0)
+                        return -errno;
+
+                xsprintf(path, "/proc/self/fdinfo/%i", subfd);
+        }
+
+        r = read_full_file(path, &fdinfo, NULL);
+        if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
+                return -EOPNOTSUPP;
+        if (r < 0)
+                return r;
+
+        p = startswith(fdinfo, "mnt_id:");
+        if (!p) {
+                p = strstr(fdinfo, "\nmnt_id:");
+                if (!p) /* The mnt_id field is a relatively new addition */
+                        return -EOPNOTSUPP;
+
+                p += 8;
+        }
+
+        p += strspn(p, WHITESPACE);
+        p[strcspn(p, WHITESPACE)] = 0;
+
+        return safe_atoi(p, mnt_id);
+}
+
+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 stat a, b;
+        int r;
+
+        assert(fd >= 0);
+        assert(filename);
+
+        /* First we will try the name_to_handle_at() syscall, which
+         * tells us the mount id and an opaque file "handle". It is
+         * not supported everywhere though (kernel compile-time
+         * option, not all file systems are hooked up). If it works
+         * the mount id is usually good enough to tell us whether
+         * something is a mount point.
+         *
+         * If that didn't work we will try to read the mount id from
+         * /proc/self/fdinfo/<fd>. 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.
+         *
+         * 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. */
+
+        r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
+        if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
+                /* This 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 nfs4), or some general name_to_handle_at() flakiness
+                 * (EINVAL): fall back to simpler logic. */
+                goto fallback_fdinfo;
+        else if (r == -EOPNOTSUPP)
+                /* 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 fallback to the traditional stat()
+                 * logic */
+                nosupp = true;
+        else if (r < 0)
+                return r;
+
+        r = name_to_handle_at_loop(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH);
+        if (r == -EOPNOTSUPP) {
+                if (nosupp)
+                        /* Neither parent nor child do name_to_handle_at()?  We have no choice but to fall back. */
+                        goto fallback_fdinfo;
+                else
+                        /* The parent can't do name_to_handle_at() but the directory we are interested in can?  If so,
+                         * it must be a mount point. */
+                        return 1;
+        } else if (r < 0)
+                return r;
+
+        /* The parent can do name_to_handle_at() but the
+         * directory we are interested in can't? If so, it
+         * must be a mount point. */
+        if (nosupp)
+                return 1;
+
+        /* If the file handle for the directory we are
+         * interested in and its parent are identical, we
+         * assume this is the root directory, which is a mount
+         * point. */
+
+        if (h->handle_bytes == h_parent->handle_bytes &&
+            h->handle_type == h_parent->handle_type &&
+            memcmp(h->f_handle, h_parent->f_handle, h->handle_bytes) == 0)
+                return 1;
+
+        return mount_id != mount_id_parent;
+
+fallback_fdinfo:
+        r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
+        if (IN_SET(r, -EOPNOTSUPP, -EACCES, -EPERM))
+                goto fallback_fstat;
+        if (r < 0)
+                return r;
+
+        r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
+        if (r < 0)
+                return r;
+
+        if (mount_id != mount_id_parent)
+                return 1;
+
+        /* 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;
+
+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)
+                return -errno;
+
+        if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
+                return -errno;
+
+        /* A directory with same device and inode as its parent? Must
+         * be the root directory */
+        if (a.st_dev == b.st_dev &&
+            a.st_ino == b.st_ino)
+                return 1;
+
+        return check_st_dev && (a.st_dev != b.st_dev);
+}
+
+/* flags can be AT_SYMLINK_FOLLOW or 0 */
+int path_is_mount_point(const char *t, const char *root, int flags) {
+        _cleanup_free_ char *canonical = NULL;
+        _cleanup_close_ int fd = -1;
+        int r;
+
+        assert(t);
+        assert((flags & ~AT_SYMLINK_FOLLOW) == 0);
+
+        if (path_equal(t, "/"))
+                return 1;
+
+        /* we need to resolve symlinks manually, we can't just rely on
+         * fd_is_mount_point() 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 & AT_SYMLINK_FOLLOW) {
+                r = chase_symlinks(t, root, CHASE_TRAIL_SLASH, &canonical);
+                if (r < 0)
+                        return r;
+
+                t = canonical;
+        }
+
+        fd = open_parent(t, O_PATH|O_CLOEXEC, 0);
+        if (fd < 0)
+                return -errno;
+
+        return fd_is_mount_point(fd, last_path_component(t), flags);
+}
+
+int path_get_mnt_id(const char *path, int *ret) {
+        int r;
+
+        r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0);
+        if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) /* kernel/fs don't support this, or seccomp blocks access, or untriggered mount, or name_to_handle_at() is flaky */
+                return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);
+
+        return r;
+}
+
+bool fstype_is_network(const char *fstype) {
+        const char *x;
+
+        x = startswith(fstype, "fuse.");
+        if (x)
+                fstype = x;
+
+        return STR_IN_SET(fstype,
+                          "afs",
+                          "cifs",
+                          "smbfs",
+                          "sshfs",
+                          "ncpfs",
+                          "ncp",
+                          "nfs",
+                          "nfs4",
+                          "gfs",
+                          "gfs2",
+                          "glusterfs",
+                          "pvfs2", /* OrangeFS */
+                          "ocfs2",
+                          "lustre");
+}
+
+bool fstype_is_api_vfs(const char *fstype) {
+        return STR_IN_SET(fstype,
+                          "autofs",
+                          "bpf",
+                          "cgroup",
+                          "cgroup2",
+                          "configfs",
+                          "cpuset",
+                          "debugfs",
+                          "devpts",
+                          "devtmpfs",
+                          "efivarfs",
+                          "fusectl",
+                          "hugetlbfs",
+                          "mqueue",
+                          "proc",
+                          "pstore",
+                          "ramfs",
+                          "securityfs",
+                          "sysfs",
+                          "tmpfs",
+                          "tracefs");
+}
+
+bool fstype_is_ro(const char *fstype) {
+        /* All Linux file systems that are necessarily read-only */
+        return STR_IN_SET(fstype,
+                          "DM_verity_hash",
+                          "iso9660",
+                          "squashfs");
+}
+
+bool fstype_can_discard(const char *fstype) {
+        return STR_IN_SET(fstype,
+                          "btrfs",
+                          "ext4",
+                          "vfat",
+                          "xfs");
+}
+
+bool fstype_can_uid_gid(const char *fstype) {
+
+        /* All file systems that have a uid=/gid= mount option that fixates the owners of all files and directories,
+         * current and future. */
+
+        return STR_IN_SET(fstype,
+                          "adfs",
+                          "fat",
+                          "hfs",
+                          "hpfs",
+                          "iso9660",
+                          "msdos",
+                          "ntfs",
+                          "vfat");
+}
+
+int dev_is_devtmpfs(void) {
+        _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+        int mount_id, r;
+        char *e;
+
+        r = path_get_mnt_id("/dev", &mount_id);
+        if (r < 0)
+                return r;
+
+        proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+        if (!proc_self_mountinfo)
+                return -errno;
+
+        (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER);
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL;
+                int mid;
+
+                r = read_line(proc_self_mountinfo, LONG_LINE_MAX, &line);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                if (sscanf(line, "%i", &mid) != 1)
+                        continue;
+
+                if (mid != mount_id)
+                        continue;
+
+                e = strstr(line, " - ");
+                if (!e)
+                        continue;
+
+                /* accept any name that starts with the currently expected type */
+                if (startswith(e + 3, "devtmpfs"))
+                        return true;
+        }
+
+        return false;
+}
+
+const char *mount_propagation_flags_to_string(unsigned long flags) {
+
+        switch (flags & (MS_SHARED|MS_SLAVE|MS_PRIVATE)) {
+        case 0:
+                return "";
+        case MS_SHARED:
+                return "shared";
+        case MS_SLAVE:
+                return "slave";
+        case MS_PRIVATE:
+                return "private";
+        }
+
+        return NULL;
+}
+
+int mount_propagation_flags_from_string(const char *name, unsigned long *ret) {
+
+        if (isempty(name))
+                *ret = 0;
+        else if (streq(name, "shared"))
+                *ret = MS_SHARED;
+        else if (streq(name, "slave"))
+                *ret = MS_SLAVE;
+        else if (streq(name, "private"))
+                *ret = MS_PRIVATE;
+        else
+                return -EINVAL;
+        return 0;
+}
diff --git a/src/basic/mountpoint-util.h b/src/basic/mountpoint-util.h
new file mode 100644 (file)
index 0000000..5398836
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags);
+
+int path_get_mnt_id(const char *path, int *ret);
+
+int fd_is_mount_point(int fd, const char *filename, int flags);
+int path_is_mount_point(const char *path, const char *root, int flags);
+
+bool fstype_is_network(const char *fstype);
+bool fstype_is_api_vfs(const char *fstype);
+bool fstype_is_ro(const char *fsype);
+bool fstype_can_discard(const char *fstype);
+bool fstype_can_uid_gid(const char *fstype);
+
+int dev_is_devtmpfs(void);
+
+const char *mount_propagation_flags_to_string(unsigned long flags);
+int mount_propagation_flags_from_string(const char *name, unsigned long *ret);
index 1503f1032a8282b5b006b1cb95808b28b784139b..0c957c9b3a8c22588ddab818f90ecf8f92f5f344 100644 (file)
@@ -15,7 +15,7 @@
 #include "fd-util.h"
 #include "log.h"
 #include "macro.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "stat-util.h"
index 5c1748542e294b25ebda58cfedfb80528e2a4c3e..3d8348e0b7fc0229b90a66ccae87b1b9d5eb4c85 100644 (file)
@@ -23,6 +23,7 @@
 #include "mkdir.h"
 #include "mount-util.h"
 #include "mount.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
index 31f9099b98e872e8a9422df9f20f4f1cf510f378..11301e4b693679d91f73ed1d6c964030a2b65c12 100644 (file)
@@ -27,7 +27,7 @@
 #include "ioprio.h"
 #include "journal-util.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "namespace.h"
 #include "parse-util.h"
 #include "path-util.h"
index 067d36dad51b72d123ab1743bb1cd450c9c11470..273d0b96fc79fdb7537a599d9a49866959244daa 100644 (file)
@@ -38,7 +38,7 @@
 #include "load-fragment.h"
 #include "log.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
index 4dfdc475baf8ea930d5ca25e77e50d25c4586952..aae548064e5035fb7c9f9d2898d68e3528073903 100644 (file)
@@ -15,7 +15,7 @@
 #include "machine-id-setup.h"
 #include "macro.h"
 #include "mkdir.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "stat-util.h"
index e15d94d98a2b226c977f8d270658bdd96efc77ad..a118d83b1b186b423b54e034ba6cba3d24f1075a 100644 (file)
@@ -20,7 +20,7 @@
 #include "missing.h"
 #include "mkdir.h"
 #include "mount-setup.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "set.h"
 #include "smack-util.h"
index 8c19150112c72ea01aa4063e1b9c534ecdd41653..99b2aa0904c39a78782b498802ca143cb9f441f3 100644 (file)
@@ -20,8 +20,8 @@
 #include "manager.h"
 #include "mkdir.h"
 #include "mount-setup.h"
-#include "mount-util.h"
 #include "mount.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
index 01516072a05844054be5c779bb22565e08dd80fe..c2ca3e0334c5631ae0a3d0090921afc292e957b5 100644 (file)
@@ -20,6 +20,7 @@
 #include "missing.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "namespace.h"
 #include "path-util.h"
 #include "selinux-util.h"
index bd4e4e7257dfd5a657220a820285dde05cf8dde1..7af0195aab83530247b6da40dae54a1089b84cd8 100644 (file)
@@ -25,6 +25,7 @@
 #include "linux-3.13/dm-ioctl.h"
 #include "mount-setup.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "signal-util.h"
index c74ad075c045a52cb9722a6cc5c52b808557296d..85cc36d80d5bc7ad8c52a003f5847dc324aae14a 100644 (file)
@@ -18,6 +18,7 @@
 #include "mkdir.h"
 #include "mount-setup.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
index 1ca071e9991686742d5a3debabc2f0f1f70f24fe..d1889273986dc4e81461ddecafc87e4b38d16968 100644 (file)
@@ -23,7 +23,7 @@
 #include "gpt.h"
 #include "missing.h"
 #include "mkdir.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
index 3ab3ce0dca1a6d6d90c57bd5c012c8539229a731..fcf9b761ee9fb6e20085ee6c9ab52934faaa64cd 100644 (file)
@@ -18,7 +18,7 @@
 #include "hashmap.h"
 #include "io-util.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "set.h"
 #include "socket-util.h"
 #include "string-util.h"
index edb62a2d30d78ed3939080f77afb736f44ba08e6..5e58e4baadbf1f02a937d8159adb9ec9de5c8b2f 100644 (file)
@@ -10,7 +10,7 @@
 #include "label.h"
 #include "main-func.h"
 #include "mkdir.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "selinux-util.h"
index 4d53bc5597b0044628694d1a933f63beb3bfd1c9..bbbc91c38e3ed4ed1f07fdee851e4c872da32f01 100644 (file)
@@ -17,6 +17,7 @@
 #include "fstab-util.h"
 #include "main-func.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-util.h"
index 53c42f0ee478e08a955ee53172dd41c376193c13..97fa092caeee344da448c4ec2eb5c1d42b1d4e90 100644 (file)
@@ -8,6 +8,7 @@
 #include "fs-util.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "nspawn-cgroup.h"
 #include "nspawn-mount.h"
 #include "path-util.h"
index 48187079b37735875c39a645ea0abd9b23763b4a..f85c0d9ab30e24531bbaaf6ea2aad0a456cac13f 100644 (file)
@@ -11,6 +11,7 @@
 #include "label.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "nspawn-mount.h"
 #include "parse-util.h"
 #include "path-util.h"
index 6eddae49d993cf6dec0d5d1528bbec18913006c5..8c6a74bea21975d93f505383c4d31f07d04d310e 100644 (file)
@@ -60,6 +60,7 @@
 #include "missing.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "netlink-util.h"
 #include "nspawn-cgroup.h"
 #include "nspawn-def.h"
index 8e04eb3c23c72bcae15f4bc915360e38957ff401..7e5642fe800ed82f45d0c8c900c08f1ecf81aee6 100644 (file)
@@ -19,7 +19,7 @@
 #include "format-util.h"
 #include "log.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "pretty-print.h"
index d11b8c26c7457208858f256002ddb54b975c36fb..78a2be341cd2da4afcd034c729311ca0aa76fc17 100644 (file)
@@ -17,7 +17,7 @@
 #include "in-addr-util.h"
 #include "list.h"
 #include "locale-util.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "nsflags.h"
 #include "parse-util.h"
 #include "path-util.h"
index 760be38c85d052095f6b950dca5a1b9337cf5671..b9ef0243a3a8bbc3eb63245b7b4b3be691b1952e 100644 (file)
@@ -28,7 +28,7 @@
 #include "escape.h"
 #include "fd-util.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "nsflags.h"
 #include "parse-util.h"
 #include "proc-cmdline.h"
index ecc32beadfb6dd623160c463de9b79d1f04dca4b..35c9aa4caf537981865c765287bd0a7ac817d169 100644 (file)
@@ -30,7 +30,7 @@
 #include "ima-util.h"
 #include "list.h"
 #include "macro.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
index 18620a3b195ea472b0cf1a4aa8ff466bd1594269..384c7ecf4ef9a488a9e9bf49c5daede5d22daffc 100644 (file)
@@ -26,6 +26,7 @@
 #include "id128-util.h"
 #include "linux-3.13/dm-ioctl.h"
 #include "missing.h"
+#include "mountpoint-util.h"
 #include "mount-util.h"
 #include "os-util.h"
 #include "path-util.h"
index c0dfa4bc4862b3ae94eeb715978c0fd1b7e1c85e..ee31c448fc80b3fee8548254e09b0927a684b870 100644 (file)
@@ -16,6 +16,7 @@
 #include "missing.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "stdio-util.h"
index ade905733ed910b3266629ccbf79f7c79000cc23..410f4fc344cc9f6be1b3fa5eb3d4630005b86e5f 100644 (file)
@@ -213,6 +213,10 @@ tests += [
          [],
          []],
 
+        [['src/test/test-mountpoint-util.c'],
+         [],
+         []],
+
         [['src/test/test-exec-util.c'],
          [],
          []],
index 56e385aa11703bb886bd3fb63c26ba1683edbc84..6986405dc6c89f685195f2c5ca54185bc76d9ddd 100644 (file)
 #include <sys/mount.h>
 
 #include "alloc-util.h"
-#include "def.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "hashmap.h"
-#include "log.h"
-#include "log.h"
 #include "mount-util.h"
-#include "path-util.h"
-#include "rm-rf.h"
 #include "string-util.h"
 #include "tests.h"
 
-static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) {
-        long unsigned flags;
-
-        assert_se(mount_propagation_flags_from_string(name, &flags) == ret);
-
-        if (ret >= 0) {
-                const char *c;
-
-                assert_se(flags == expected);
-
-                c = mount_propagation_flags_to_string(flags);
-                if (isempty(name))
-                        assert_se(isempty(c));
-                else
-                        assert_se(streq(c, name));
-        }
-}
-
-static void test_mnt_id(void) {
-        _cleanup_fclose_ FILE *f = NULL;
-        Hashmap *h;
-        Iterator i;
-        char *p;
-        void *k;
-        int r;
-
-        assert_se(f = fopen("/proc/self/mountinfo", "re"));
-        assert_se(h = hashmap_new(&trivial_hash_ops));
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL, *path = NULL;
-                int mnt_id;
-
-                r = read_line(f, LONG_LINE_MAX, &line);
-                if (r == 0)
-                        break;
-                assert_se(r > 0);
-
-                assert_se(sscanf(line, "%i %*s %*s %*s %ms", &mnt_id, &path) == 2);
-
-                assert_se(hashmap_put(h, INT_TO_PTR(mnt_id), path) >= 0);
-                path = NULL;
-        }
-
-        HASHMAP_FOREACH_KEY(p, k, h, i) {
-                int mnt_id = PTR_TO_INT(k), mnt_id2;
-
-                r = path_get_mnt_id(p, &mnt_id2);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to get the mnt id of %s: %m\n", p);
-                        continue;
-                }
-
-                log_debug("mnt id of %s is %i\n", p, mnt_id2);
-
-                if (mnt_id == mnt_id2)
-                        continue;
-
-                /* The ids don't match? If so, then there are two mounts on the same path, let's check if that's really
-                 * the case */
-                assert_se(path_equal_ptr(hashmap_get(h, INT_TO_PTR(mnt_id2)), p));
-        }
-
-        hashmap_free_free(h);
-}
-
-static void test_path_is_mount_point(void) {
-        int fd;
-        char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
-        _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
-        _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
-        _cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
-
-        assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/", NULL, 0) > 0);
-        assert_se(path_is_mount_point("//", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("//", NULL, 0) > 0);
-
-        assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/proc", NULL, 0) > 0);
-        assert_se(path_is_mount_point("/proc/", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/proc/", NULL, 0) > 0);
-
-        assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0);
-        assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0);
-
-        assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/sys", NULL, 0) > 0);
-        assert_se(path_is_mount_point("/sys/", NULL, AT_SYMLINK_FOLLOW) > 0);
-        assert_se(path_is_mount_point("/sys/", NULL, 0) > 0);
-
-        /* we'll create a hierarchy of different kinds of dir/file/link
-         * layouts:
-         *
-         * <tmp>/file1, <tmp>/file2
-         * <tmp>/link1 -> file1, <tmp>/link2 -> file2
-         * <tmp>/dir1/
-         * <tmp>/dir1/file
-         * <tmp>/dirlink1 -> dir1
-         * <tmp>/dirlink1file -> dirlink1/file
-         * <tmp>/dir2/
-         * <tmp>/dir2/file
-         */
-
-        /* file mountpoints */
-        assert_se(mkdtemp(tmp_dir) != NULL);
-        file1 = path_join(NULL, tmp_dir, "file1");
-        assert_se(file1);
-        file2 = path_join(NULL, tmp_dir, "file2");
-        assert_se(file2);
-        fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
-        assert_se(fd > 0);
-        close(fd);
-        fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
-        assert_se(fd > 0);
-        close(fd);
-        link1 = path_join(NULL, tmp_dir, "link1");
-        assert_se(link1);
-        assert_se(symlink("file1", link1) == 0);
-        link2 = path_join(NULL, tmp_dir, "link2");
-        assert_se(link1);
-        assert_se(symlink("file2", link2) == 0);
-
-        assert_se(path_is_mount_point(file1, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(file1, NULL, 0) == 0);
-        assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(link1, NULL, 0) == 0);
-
-        /* directory mountpoints */
-        dir1 = path_join(NULL, tmp_dir, "dir1");
-        assert_se(dir1);
-        assert_se(mkdir(dir1, 0755) == 0);
-        dirlink1 = path_join(NULL, tmp_dir, "dirlink1");
-        assert_se(dirlink1);
-        assert_se(symlink("dir1", dirlink1) == 0);
-        dirlink1file = path_join(NULL, tmp_dir, "dirlink1file");
-        assert_se(dirlink1file);
-        assert_se(symlink("dirlink1/file", dirlink1file) == 0);
-        dir2 = path_join(NULL, tmp_dir, "dir2");
-        assert_se(dir2);
-        assert_se(mkdir(dir2, 0755) == 0);
-
-        assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(dir1, NULL, 0) == 0);
-        assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0);
-
-        /* file in subdirectory mountpoints */
-        dir1file = path_join(NULL, dir1, "file");
-        assert_se(dir1file);
-        fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
-        assert_se(fd > 0);
-        close(fd);
-
-        assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(dir1file, NULL, 0) == 0);
-        assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0);
-        assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0);
-
-        /* these tests will only work as root */
-        if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
-                int rf, rt, rdf, rdt, rlf, rlt, rl1f, rl1t;
-                const char *file2d;
-
-                /* files */
-                /* capture results in vars, to avoid dangling mounts on failure */
-                log_info("%s: %s", __func__, file2);
-                rf = path_is_mount_point(file2, NULL, 0);
-                rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW);
-
-                file2d = strjoina(file2, "/");
-                log_info("%s: %s", __func__, file2d);
-                rdf = path_is_mount_point(file2d, NULL, 0);
-                rdt = path_is_mount_point(file2d, NULL, AT_SYMLINK_FOLLOW);
-
-                log_info("%s: %s", __func__, link2);
-                rlf = path_is_mount_point(link2, NULL, 0);
-                rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW);
-
-                assert_se(umount(file2) == 0);
-
-                assert_se(rf == 1);
-                assert_se(rt == 1);
-                assert_se(rdf == -ENOTDIR);
-                assert_se(rdt == -ENOTDIR);
-                assert_se(rlf == 0);
-                assert_se(rlt == 1);
-
-                /* dirs */
-                dir2file = path_join(NULL, dir2, "file");
-                assert_se(dir2file);
-                fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
-                assert_se(fd > 0);
-                close(fd);
-
-                assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
-
-                log_info("%s: %s", __func__, dir1);
-                rf = path_is_mount_point(dir1, NULL, 0);
-                rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW);
-                log_info("%s: %s", __func__, dirlink1);
-                rlf = path_is_mount_point(dirlink1, NULL, 0);
-                rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW);
-                log_info("%s: %s", __func__, dirlink1file);
-                /* its parent is a mount point, but not /file itself */
-                rl1f = path_is_mount_point(dirlink1file, NULL, 0);
-                rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW);
-
-                assert_se(umount(dir1) == 0);
-
-                assert_se(rf == 1);
-                assert_se(rt == 1);
-                assert_se(rlf == 0);
-                assert_se(rlt == 1);
-                assert_se(rl1f == 0);
-                assert_se(rl1t == 0);
-
-        } else
-                printf("Skipping bind mount file test: %m\n");
-
-        assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
-}
-
 static void test_mount_option_mangle(void) {
         char *opts = NULL;
         unsigned long f;
@@ -295,19 +62,8 @@ static void test_mount_option_mangle(void) {
 }
 
 int main(int argc, char *argv[]) {
-
         test_setup_logging(LOG_DEBUG);
 
-        test_mount_propagation_flags("shared", 0, MS_SHARED);
-        test_mount_propagation_flags("slave", 0, MS_SLAVE);
-        test_mount_propagation_flags("private", 0, MS_PRIVATE);
-        test_mount_propagation_flags(NULL, 0, 0);
-        test_mount_propagation_flags("", 0, 0);
-        test_mount_propagation_flags("xxxx", -EINVAL, 0);
-        test_mount_propagation_flags(" ", -EINVAL, 0);
-
-        test_mnt_id();
-        test_path_is_mount_point();
         test_mount_option_mangle();
 
         return 0;
diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c
new file mode 100644 (file)
index 0000000..b8b37cf
--- /dev/null
@@ -0,0 +1,258 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <sys/mount.h>
+
+#include "alloc-util.h"
+#include "def.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
+#include "log.h"
+#include "log.h"
+#include "mountpoint-util.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "tests.h"
+
+static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) {
+        long unsigned flags;
+
+        assert_se(mount_propagation_flags_from_string(name, &flags) == ret);
+
+        if (ret >= 0) {
+                const char *c;
+
+                assert_se(flags == expected);
+
+                c = mount_propagation_flags_to_string(flags);
+                if (isempty(name))
+                        assert_se(isempty(c));
+                else
+                        assert_se(streq(c, name));
+        }
+}
+
+static void test_mnt_id(void) {
+        _cleanup_fclose_ FILE *f = NULL;
+        Hashmap *h;
+        Iterator i;
+        char *p;
+        void *k;
+        int r;
+
+        assert_se(f = fopen("/proc/self/mountinfo", "re"));
+        assert_se(h = hashmap_new(&trivial_hash_ops));
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL, *path = NULL;
+                int mnt_id;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r == 0)
+                        break;
+                assert_se(r > 0);
+
+                assert_se(sscanf(line, "%i %*s %*s %*s %ms", &mnt_id, &path) == 2);
+
+                assert_se(hashmap_put(h, INT_TO_PTR(mnt_id), path) >= 0);
+                path = NULL;
+        }
+
+        HASHMAP_FOREACH_KEY(p, k, h, i) {
+                int mnt_id = PTR_TO_INT(k), mnt_id2;
+
+                r = path_get_mnt_id(p, &mnt_id2);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to get the mnt id of %s: %m\n", p);
+                        continue;
+                }
+
+                log_debug("mnt id of %s is %i\n", p, mnt_id2);
+
+                if (mnt_id == mnt_id2)
+                        continue;
+
+                /* The ids don't match? If so, then there are two mounts on the same path, let's check if that's really
+                 * the case */
+                assert_se(path_equal_ptr(hashmap_get(h, INT_TO_PTR(mnt_id2)), p));
+        }
+
+        hashmap_free_free(h);
+}
+
+static void test_path_is_mount_point(void) {
+        int fd;
+        char tmp_dir[] = "/tmp/test-path-is-mount-point-XXXXXX";
+        _cleanup_free_ char *file1 = NULL, *file2 = NULL, *link1 = NULL, *link2 = NULL;
+        _cleanup_free_ char *dir1 = NULL, *dir1file = NULL, *dirlink1 = NULL, *dirlink1file = NULL;
+        _cleanup_free_ char *dir2 = NULL, *dir2file = NULL;
+
+        assert_se(path_is_mount_point("/", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/", NULL, 0) > 0);
+        assert_se(path_is_mount_point("//", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("//", NULL, 0) > 0);
+
+        assert_se(path_is_mount_point("/proc", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/proc", NULL, 0) > 0);
+        assert_se(path_is_mount_point("/proc/", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/proc/", NULL, 0) > 0);
+
+        assert_se(path_is_mount_point("/proc/1", NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point("/proc/1", NULL, 0) == 0);
+        assert_se(path_is_mount_point("/proc/1/", NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point("/proc/1/", NULL, 0) == 0);
+
+        assert_se(path_is_mount_point("/sys", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/sys", NULL, 0) > 0);
+        assert_se(path_is_mount_point("/sys/", NULL, AT_SYMLINK_FOLLOW) > 0);
+        assert_se(path_is_mount_point("/sys/", NULL, 0) > 0);
+
+        /* we'll create a hierarchy of different kinds of dir/file/link
+         * layouts:
+         *
+         * <tmp>/file1, <tmp>/file2
+         * <tmp>/link1 -> file1, <tmp>/link2 -> file2
+         * <tmp>/dir1/
+         * <tmp>/dir1/file
+         * <tmp>/dirlink1 -> dir1
+         * <tmp>/dirlink1file -> dirlink1/file
+         * <tmp>/dir2/
+         * <tmp>/dir2/file
+         */
+
+        /* file mountpoints */
+        assert_se(mkdtemp(tmp_dir) != NULL);
+        file1 = path_join(NULL, tmp_dir, "file1");
+        assert_se(file1);
+        file2 = path_join(NULL, tmp_dir, "file2");
+        assert_se(file2);
+        fd = open(file1, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+        assert_se(fd > 0);
+        close(fd);
+        fd = open(file2, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+        assert_se(fd > 0);
+        close(fd);
+        link1 = path_join(NULL, tmp_dir, "link1");
+        assert_se(link1);
+        assert_se(symlink("file1", link1) == 0);
+        link2 = path_join(NULL, tmp_dir, "link2");
+        assert_se(link1);
+        assert_se(symlink("file2", link2) == 0);
+
+        assert_se(path_is_mount_point(file1, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(file1, NULL, 0) == 0);
+        assert_se(path_is_mount_point(link1, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(link1, NULL, 0) == 0);
+
+        /* directory mountpoints */
+        dir1 = path_join(NULL, tmp_dir, "dir1");
+        assert_se(dir1);
+        assert_se(mkdir(dir1, 0755) == 0);
+        dirlink1 = path_join(NULL, tmp_dir, "dirlink1");
+        assert_se(dirlink1);
+        assert_se(symlink("dir1", dirlink1) == 0);
+        dirlink1file = path_join(NULL, tmp_dir, "dirlink1file");
+        assert_se(dirlink1file);
+        assert_se(symlink("dirlink1/file", dirlink1file) == 0);
+        dir2 = path_join(NULL, tmp_dir, "dir2");
+        assert_se(dir2);
+        assert_se(mkdir(dir2, 0755) == 0);
+
+        assert_se(path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(dir1, NULL, 0) == 0);
+        assert_se(path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(dirlink1, NULL, 0) == 0);
+
+        /* file in subdirectory mountpoints */
+        dir1file = path_join(NULL, dir1, "file");
+        assert_se(dir1file);
+        fd = open(dir1file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+        assert_se(fd > 0);
+        close(fd);
+
+        assert_se(path_is_mount_point(dir1file, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(dir1file, NULL, 0) == 0);
+        assert_se(path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW) == 0);
+        assert_se(path_is_mount_point(dirlink1file, NULL, 0) == 0);
+
+        /* these tests will only work as root */
+        if (mount(file1, file2, NULL, MS_BIND, NULL) >= 0) {
+                int rf, rt, rdf, rdt, rlf, rlt, rl1f, rl1t;
+                const char *file2d;
+
+                /* files */
+                /* capture results in vars, to avoid dangling mounts on failure */
+                log_info("%s: %s", __func__, file2);
+                rf = path_is_mount_point(file2, NULL, 0);
+                rt = path_is_mount_point(file2, NULL, AT_SYMLINK_FOLLOW);
+
+                file2d = strjoina(file2, "/");
+                log_info("%s: %s", __func__, file2d);
+                rdf = path_is_mount_point(file2d, NULL, 0);
+                rdt = path_is_mount_point(file2d, NULL, AT_SYMLINK_FOLLOW);
+
+                log_info("%s: %s", __func__, link2);
+                rlf = path_is_mount_point(link2, NULL, 0);
+                rlt = path_is_mount_point(link2, NULL, AT_SYMLINK_FOLLOW);
+
+                assert_se(umount(file2) == 0);
+
+                assert_se(rf == 1);
+                assert_se(rt == 1);
+                assert_se(rdf == -ENOTDIR);
+                assert_se(rdt == -ENOTDIR);
+                assert_se(rlf == 0);
+                assert_se(rlt == 1);
+
+                /* dirs */
+                dir2file = path_join(NULL, dir2, "file");
+                assert_se(dir2file);
+                fd = open(dir2file, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0664);
+                assert_se(fd > 0);
+                close(fd);
+
+                assert_se(mount(dir2, dir1, NULL, MS_BIND, NULL) >= 0);
+
+                log_info("%s: %s", __func__, dir1);
+                rf = path_is_mount_point(dir1, NULL, 0);
+                rt = path_is_mount_point(dir1, NULL, AT_SYMLINK_FOLLOW);
+                log_info("%s: %s", __func__, dirlink1);
+                rlf = path_is_mount_point(dirlink1, NULL, 0);
+                rlt = path_is_mount_point(dirlink1, NULL, AT_SYMLINK_FOLLOW);
+                log_info("%s: %s", __func__, dirlink1file);
+                /* its parent is a mount point, but not /file itself */
+                rl1f = path_is_mount_point(dirlink1file, NULL, 0);
+                rl1t = path_is_mount_point(dirlink1file, NULL, AT_SYMLINK_FOLLOW);
+
+                assert_se(umount(dir1) == 0);
+
+                assert_se(rf == 1);
+                assert_se(rt == 1);
+                assert_se(rlf == 0);
+                assert_se(rlt == 1);
+                assert_se(rl1f == 0);
+                assert_se(rl1t == 0);
+
+        } else
+                printf("Skipping bind mount file test: %m\n");
+
+        assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
+}
+
+int main(int argc, char *argv[]) {
+        test_setup_logging(LOG_DEBUG);
+
+        test_mount_propagation_flags("shared", 0, MS_SHARED);
+        test_mount_propagation_flags("slave", 0, MS_SLAVE);
+        test_mount_propagation_flags("private", 0, MS_PRIVATE);
+        test_mount_propagation_flags(NULL, 0, 0);
+        test_mount_propagation_flags("", 0, 0);
+        test_mount_propagation_flags("xxxx", -EINVAL, 0);
+        test_mount_propagation_flags(" ", -EINVAL, 0);
+
+        test_mnt_id();
+        test_path_is_mount_point();
+
+        return 0;
+}
index 7feae54068fce39b1207514157450c9dd9a85a21..d2ccb41fd9e6da3e3e5f6f074239e795fdf46296 100644 (file)
@@ -6,7 +6,7 @@
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "macro.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "stat-util.h"
index 2b0564d8a05b0d81a7adf4a4c5c898d81fa52b1e..2f0538a4bba0252afa2879fecfa1c12393b9da57 100644 (file)
@@ -9,7 +9,7 @@
 #include "fileio.h"
 #include "macro.h"
 #include "missing.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "stat-util.h"
 
 static void test_files_same(void) {
index eeeb1d18506f4efacb07be4827ef2a59c55f295f..e31af282a4d471daa0f8a1c204891e5f66a307c3 100644 (file)
@@ -41,7 +41,7 @@
 #include "macro.h"
 #include "missing.h"
 #include "mkdir.h"
-#include "mount-util.h"
+#include "mountpoint-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-lookup.h"
index ffe63d5717a4e3a0a7ed9a8769d8bf60d8ee60e8..5da9ce1681de676de9217ee73b0cf23ed806e39c 100644 (file)
@@ -7,6 +7,7 @@
 #include "main-func.h"
 #include "mkdir.h"
 #include "mount-util.h"
+#include "mountpoint-util.h"
 #include "path-util.h"
 #include "stat-util.h"
 #include "string-util.h"