]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: cleanup all stat() use
authorKarel Zak <kzak@redhat.com>
Tue, 18 Apr 2023 13:54:25 +0000 (15:54 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 18 Apr 2023 13:54:25 +0000 (15:54 +0200)
* don't use STATX_MODE as we need only file type
* use fstatat() or stat() as fallback on EOPNOTSUPP
* use st_rdev from statx() too

* rename to mnt_stat_mountpoint() to more generic mnt_safe_stat()

* use mnt_is_path() on more places
* cleanup mnt_context_*_excode() to not use stat()
* use on others places mnt_safe_stat()

Note that on some places stat() remaining, but it's not related to the
mountpoints, it's about /run/mount/utab permissions, file locking and
/dev/* permissions for non-root mounts.

Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/context.c
libmount/src/context_mount.c
libmount/src/context_umount.c
libmount/src/mountP.h
libmount/src/tab.c
libmount/src/tab_parse.c
libmount/src/utils.c

index 2df4716a7135421c494066c458a099eb0dae83ef..4c5e65659f5b60d1f285e2d44334921fe9b3d955 100644 (file)
@@ -1407,7 +1407,7 @@ int mnt_context_get_mountinfo_for_target(struct libmnt_context *cxt,
        if (mnt_context_is_nocanonicalize(cxt))
                mnt_context_set_tabfilter(cxt, mountinfo_filter, (void *) tgt);
 
-       else if (mnt_stat_mountpoint(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
+       else if (mnt_safe_stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
                cache = mnt_context_get_cache(cxt);
                cn_tgt = mnt_resolve_path(tgt, cache);
                if (cn_tgt)
@@ -2025,34 +2025,32 @@ int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
        if (!ns_old)
                return -MNT_ERR_NAMESPACE;
 
-       /* Ignore errors when search in $PATH and do not modify
-        * @rc due to stat() etc.
+       /* Ignore errors when search in $PATH and do not modify @rc
         */
        path = strtok_r(search_path, ":", &p);
        while (path) {
                char helper[PATH_MAX];
-               struct stat st;
-               int xrc;
+               int len, found = 0;
 
-               xrc = snprintf(helper, sizeof(helper), "%s/%s.%s",
+               len = snprintf(helper, sizeof(helper), "%s/%s.%s",
                                                path, name, type);
                path = strtok_r(NULL, ":", &p);
 
-               if (xrc < 0 || (size_t) xrc >= sizeof(helper))
+               if (len < 0 || (size_t) len >= sizeof(helper))
                        continue;
 
-               xrc = stat(helper, &st);
-               if (xrc == -1 && errno == ENOENT && strchr(type, '.')) {
+               found = mnt_is_path(helper);
+               if (!found && strchr(type, '.')) {
                        /* If type ends with ".subtype" try without it */
                        char *hs = strrchr(helper, '.');
                        if (hs)
                                *hs = '\0';
-                       xrc = stat(helper, &st);
+                       found = mnt_is_path(helper);
                }
 
                DBG(CXT, ul_debugobj(cxt, "%-25s ... %s", helper,
-                                       xrc ? "not found" : "found"));
-               if (xrc)
+                                       found ? "found" : "not found"));
+               if (!found)
                        continue;
 
                /* success */
index 7bda266825fb15611a328954efd4bd9634f42c15..b8499471af52b14b07daada62ba3e08a18fffba1 100644 (file)
@@ -1558,7 +1558,7 @@ int mnt_context_get_mount_excode(
                if (!buf)
                        break;
                if (geteuid() == 0) {
-                       if (mnt_stat_mountpoint(tgt, &st) || !S_ISDIR(st.st_mode))
+                       if (mnt_safe_stat(tgt, &st) || !S_ISDIR(st.st_mode))
                                snprintf(buf, bufsz, _("mount point is not a directory"));
                        else
                                snprintf(buf, bufsz, _("permission denied"));
@@ -1584,13 +1584,13 @@ int mnt_context_get_mount_excode(
                        snprintf(buf, bufsz, _("%s already mounted or mount point busy"), src);
                break;
        case ENOENT:
-               if (tgt && mnt_lstat_mountpoint(tgt, &st)) {
+               if (tgt && mnt_safe_lstat(tgt, &st)) {
                        if (buf)
                                snprintf(buf, bufsz, _("mount point does not exist"));
-               } else if (tgt && mnt_stat_mountpoint(tgt, &st)) {
+               } else if (tgt && mnt_safe_stat(tgt, &st)) {
                        if (buf)
                                snprintf(buf, bufsz, _("mount point is a symbolic link to nowhere"));
-               } else if (src && stat(src, &st)) {
+               } else if (src && !mnt_is_path(src)) {
                        if (uflags & MNT_MS_NOFAIL)
                                return MNT_EX_SUCCESS;
                        if (buf)
@@ -1602,10 +1602,10 @@ int mnt_context_get_mount_excode(
                break;
 
        case ENOTDIR:
-               if (mnt_stat_mountpoint(tgt, &st) || ! S_ISDIR(st.st_mode)) {
+               if (mnt_safe_stat(tgt, &st) || ! S_ISDIR(st.st_mode)) {
                        if (buf)
                                snprintf(buf, bufsz, _("mount point is not a directory"));
-               } else if (src && stat(src, &st) && errno == ENOTDIR) {
+               } else if (src && !mnt_is_path(src)) {
                        if (uflags & MNT_MS_NOFAIL)
                                return MNT_EX_SUCCESS;
                        if (buf)
@@ -1664,7 +1664,7 @@ int mnt_context_get_mount_excode(
                        return MNT_EX_SUCCESS;
                if (!buf)
                        break;
-               if (src && stat(src, &st))
+               if (src && mnt_safe_stat(src, &st))
                        snprintf(buf, bufsz, _("%s is not a block device, and stat(2) fails?"), src);
                else if (src && S_ISBLK(st.st_mode))
                        snprintf(buf, bufsz,
@@ -1710,7 +1710,7 @@ int mnt_context_get_mount_excode(
 
        case EBADMSG:
                /* Bad CRC for classic filesystems (e.g. extN or XFS) */
-               if (buf && src && stat(src, &st) == 0
+               if (buf && src && mnt_safe_stat(src, &st) == 0
                    && (S_ISBLK(st.st_mode) || S_ISREG(st.st_mode))) {
                        snprintf(buf, bufsz, _("cannot mount; probably corrupted filesystem on %s"), src);
                        break;
index efb6675b3ab763a5b422b15091573c7e8d252eb3..26394d51efb71e04b5dfe612ba2fe322fbcd20d8 100644 (file)
@@ -134,7 +134,7 @@ try_loopdev:
                 */
                struct stat st;
 
-               if (mnt_stat_mountpoint(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
+               if (mnt_safe_stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
                        int count;
                        struct libmnt_cache *cache = mnt_context_get_cache(cxt);
                        const char *bf = cache ? mnt_resolve_path(tgt, cache) : tgt;
@@ -275,7 +275,7 @@ static int lookup_umount_fs_by_statfs(struct libmnt_context *cxt, const char *tg
            || mnt_context_is_lazy(cxt)
            || mnt_context_is_nocanonicalize(cxt)
            || mnt_context_is_loopdel(cxt)
-           || mnt_stat_mountpoint(tgt, &st) != 0 || !S_ISDIR(st.st_mode)
+           || mnt_safe_stat(tgt, &st) != 0 || !S_ISDIR(st.st_mode)
            || has_utab_entry(cxt, tgt))
                return 1; /* not found */
 
index 4af212388c61651c619ac2a76f707aa9294ecfc9..bceb04a92bb17ba47ae09197af1ad994421bb093 100644 (file)
@@ -128,8 +128,8 @@ extern void mnt_free_filesystems(char **filesystems);
 
 extern char *mnt_get_kernel_cmdline_option(const char *name);
 
-extern int mnt_stat_mountpoint(const char *target, struct stat *st);
-extern int mnt_lstat_mountpoint(const char *target, struct stat *st);
+extern int mnt_safe_stat(const char *target, struct stat *st);
+extern int mnt_safe_lstat(const char *target, struct stat *st);
 extern int mnt_is_path(const char *target);
 
 extern int mnt_tmptgt_unshare(int *old_ns_fd);
index d8b239b305e4c833f5e92d46dffd2087b46d6cd0..60bef8b2d16b394bb065e0becd6061dfd4b9f6c2 100644 (file)
@@ -1775,7 +1775,7 @@ int __mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_f
                struct stat st;
 
                devno = mnt_fs_get_devno(fstab_fs);
-               if (!devno && stat(src, &st) == 0 && S_ISBLK(st.st_mode))
+               if (!devno && mnt_safe_stat(src, &st) == 0 && S_ISBLK(st.st_mode))
                        devno = st.st_rdev;
        }
 
index 526a0078bb676b17c1abd1f099c54deb38456a8f..b8ec244f7971731275cd3d438d1b31efb3076f6e 100644 (file)
@@ -974,11 +974,10 @@ int mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname)
 struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt, int empty_for_enoent)
 {
        struct libmnt_table *tb;
-       struct stat st;
 
        if (!filename)
                return NULL;
-       if (stat(filename, &st))
+       if (!mnt_is_path(filename))
                return empty_for_enoent ? mnt_new_table() : NULL;
 
        tb = mnt_new_table();
@@ -1149,7 +1148,7 @@ int mnt_table_parse_fstab(struct libmnt_table *tb, const char *filename)
                filename = mnt_get_fstab_path();
        if (!filename)
                return -EINVAL;
-       if (stat(filename, &st) != 0)
+       if (mnt_safe_stat(filename, &st) != 0)
                return -errno;
 
        tb->fmt = MNT_FMT_FSTAB;
index 1fa67b85f4d4c90a37edf2338af6c72304055677..e03d9326513aa299dae7ca67d23ed5052338efed 100644 (file)
@@ -100,6 +100,10 @@ static int fstype_cmp(const void *v1, const void *v2)
        return strcmp(s1, s2);
 }
 
+/* This very simplified stat() alternative uses cached VFS data and does not
+ * directly ask the filesystem for details. It requires a kernel that supports
+ * statx(). It's usable only for file type, rdev and ino!
+ */
 static int safe_stat(const char *target, struct stat *st, int nofollow)
 {
        assert(target);
@@ -125,26 +129,28 @@ static int safe_stat(const char *target, struct stat *st, int nofollow)
                if (rc == 0) {
                        st->st_ino  = stx.stx_ino;
                        st->st_dev  = makedev(stx.stx_dev_major, stx.stx_dev_minor);
+                       st->st_rdev = makedev(stx.stx_rdev_major, stx.stx_rdev_minor);
                        st->st_mode = stx.stx_mode;
                }
-               return rc;
+
+               if (rc == 0 || errno != EOPNOTSUPP)
+                       return rc;
        }
-#else
-# ifdef AT_NO_AUTOMOUNT
+#endif
+
+#ifdef AT_NO_AUTOMOUNT
        return fstatat(AT_FDCWD, target, st,
                        AT_NO_AUTOMOUNT | (nofollow ? AT_SYMLINK_NOFOLLOW : 0));
-# else
-       return nofollow ? lstat(target, st) : stat(target, st);
-# endif
 #endif
+       return nofollow ? lstat(target, st) : stat(target, st);
 }
 
-int mnt_stat_mountpoint(const char *target, struct stat *st)
+int mnt_safe_stat(const char *target, struct stat *st)
 {
        return safe_stat(target, st, 0);
 }
 
-int mnt_lstat_mountpoint(const char *target, struct stat *st)
+int mnt_safe_lstat(const char *target, struct stat *st)
 {
        return safe_stat(target, st, 1);
 }
@@ -1074,7 +1080,7 @@ char *mnt_get_mountpoint(const char *path)
        if (*mnt == '/' && *(mnt + 1) == '\0')
                goto done;
 
-       if (mnt_stat_mountpoint(mnt, &st))
+       if (mnt_safe_stat(mnt, &st))
                goto err;
        base = st.st_dev;
 
@@ -1083,7 +1089,7 @@ char *mnt_get_mountpoint(const char *path)
 
                if (!p)
                        break;
-               if (mnt_stat_mountpoint(*mnt ? mnt : "/", &st))
+               if (mnt_safe_stat(*mnt ? mnt : "/", &st))
                        goto err;
                dir = st.st_dev;
                if (dir != base) {
@@ -1488,9 +1494,9 @@ static int tests_stat(struct libmnt_test *ts, int argc, char *argv[])
        int rc;
 
        if (strcmp(argv[0], "--lstat") == 0)
-               rc = mnt_lstat_mountpoint(path, &st);
+               rc = mnt_safe_lstat(path, &st);
        else
-               rc = mnt_stat_mountpoint(path, &st);
+               rc = mnt_safe_stat(path, &st);
        if (rc)
                printf("%s: failed: rc=%d: %m\n", path, rc);
        else {