]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: merge utab into listmount-based tables
authorKarel Zak <kzak@redhat.com>
Thu, 25 Jun 2026 12:52:21 +0000 (14:52 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 29 Jun 2026 09:13:18 +0000 (11:13 +0200)
Extract utab merge logic from __mnt_table_parse_mountinfo() into a
shared mnt_table_merge_utab() function and call it at the end of
mnt_table_fetch_listmount(). This makes userspace mount options
(x-systemd.*, user=, etc.) available when the mount table is obtained
via listmount/statmount syscalls.

The merge sets user_optstr directly (instead of the combined optstr)
to avoid conflicts with lazy statmount() which populates kernel
options on demand.

Add mnt_table_disable_useropts() public API to allow callers to skip
utab merging when only kernel-side data is needed.

Use the new API in findmnt --kernel=listmount to keep backward
compatible behavior (kernel-only data); users who want userspace
options can use --mtab.

Signed-off-by: Karel Zak <kzak@redhat.com>
(cherry picked from commit c839a9ac8fed409c332c94ec69ddc11aea97ae80)

libmount/docs/libmount-sections.txt
libmount/src/libmount.h.in
libmount/src/libmount.sym
libmount/src/mountP.h
libmount/src/tab_listmount.c
libmount/src/tab_parse.c
misc-utils/findmnt.c

index 6070362188f6157af3e9ca972fdda72cf5ca6b15..8d11867aaaf4a62c6de349bd8cb619df8ffaa77b 100644 (file)
@@ -413,6 +413,7 @@ mnt_table_next_fs
 mnt_table_over_fs
 mnt_table_parse_dir
 mnt_table_parse_file
+mnt_table_disable_useropts
 mnt_table_parse_fstab
 mnt_table_parse_mtab
 mnt_table_parse_stream
index 04b7b30749120ae5299c66ff238481659c3cf6c4..d3b39e66103b2f41fbe2c34404adf2715055e5e2 100644 (file)
@@ -608,6 +608,7 @@ extern int mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname);
 extern int mnt_table_parse_fstab(struct libmnt_table *tb, const char *filename);
 extern int mnt_table_parse_swaps(struct libmnt_table *tb, const char *filename);
 extern int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename);
+extern int mnt_table_disable_useropts(struct libmnt_table *tb, int disable);
 extern int mnt_table_set_parser_errcb(struct libmnt_table *tb,
                 int (*cb)(struct libmnt_table *tb, const char *filename, int line));
 
index 42fefc1508ec82924614270d322dc96fabcb8711..0240b5fe08506fff9c1ef0609b2aac4d77f73eaa 100644 (file)
@@ -421,3 +421,7 @@ MOUNT_2_42 {
        mnt_fs_is_attached;
        mnt_fs_is_detached;
 } MOUNT_2_41;
+
+MOUNT_2_43 {
+       mnt_table_disable_useropts;
+} MOUNT_2_42;
index 3f5a93d9459dce799baaa7d2697622bb6ef71c6e..0f6ee4f6df7285d911231b866fb2722da0c4b3a3 100644 (file)
@@ -151,6 +151,8 @@ extern int mnt_table_set_parser_fltrcb(     struct libmnt_table *tb,
 extern int __mnt_table_parse_mountinfo(struct libmnt_table *tb,
                                        const char *filename,
                                        struct libmnt_table *u_tb);
+extern int mnt_table_merge_utab(struct libmnt_table *tb,
+                               struct libmnt_table *u_tb);
 
 extern struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
                                        struct libmnt_fs *fs,
@@ -336,6 +338,7 @@ struct libmnt_table {
        struct libmnt_statmnt   *stmnt; /* statmount() stuff */
 
        int             noautofs;       /* ignore autofs mounts */
+       int             nouseropts;     /* do not merge utab */
 
        struct list_head        ents;   /* list of entries (libmnt_fs) */
        void            *userdata;
index dbbc2b8f67445f20369bdb3bf2bd39976f24b371..e2c7508fe16dacfcfea75ed85de4cfa4d58e1584 100644 (file)
@@ -408,6 +408,10 @@ int mnt_table_fetch_listmount(struct libmnt_table *tb)
         * have all the necessary data (or on error) */
        tb->lsmnt->done = 1;
 
+       /* merge userspace mount options from utab */
+       if (rc == 0)
+               rc = mnt_table_merge_utab(tb, NULL);
+
        /* restore */
        if (tb->stmnt)
                mnt_statmnt_disable_fetching(tb->stmnt, stmnt_status);
index 5077e9a350d274db1d3a8fa51c98dfde78a99ad3..c21d5d019bdb2021cd0c3a9804aac3f26f7d0257 100644 (file)
@@ -1108,6 +1108,27 @@ int mnt_table_is_noautofs(struct libmnt_table *tb)
        return tb ? tb->noautofs : 0;
 }
 
+/**
+ * mnt_table_disable_useropts:
+ * @tb: table
+ * @disable: 1 to disable, 0 to enable
+ *
+ * Disable or enable merging of userspace mount options from utab when
+ * populating the mount table. This applies to both mountinfo and
+ * listmount-based table sources.
+ *
+ * Returns: 0 on success, <0 on error.
+ *
+ * Since: 2.43
+ */
+int mnt_table_disable_useropts(struct libmnt_table *tb, int disable)
+{
+       if (!tb)
+               return -EINVAL;
+       tb->nouseropts = disable ? 1 : 0;
+       return 0;
+}
+
 /**
  * mnt_table_parse_swaps:
  * @tb: table
@@ -1231,7 +1252,9 @@ static struct libmnt_fs *mnt_table_merge_user_fs(struct libmnt_table *tb, struct
 
        if (fs) {
                DBG_OBJ(TAB, tb, ul_debug(" found"));
-               mnt_fs_append_options(fs, optstr);
+               mnt_optstr_append_option(&fs->user_optstr, optstr, NULL);
+               free(fs->optstr);
+               fs->optstr = NULL;
                mnt_fs_append_attributes(fs, attrs);
                mnt_fs_set_bindsrc(fs, mnt_fs_get_bindsrc(uf));
                fs->flags |= MNT_FS_MERGED;
@@ -1241,45 +1264,22 @@ static struct libmnt_fs *mnt_table_merge_user_fs(struct libmnt_table *tb, struct
        return fs;
 }
 
-/* default filename is /proc/self/mountinfo
+/*
+ * Read utab and merge userspace options into the mount table @tb.
+ * If @u_tb is provided, use it as utab; otherwise read from
+ * /run/mount/utab.
  */
-int __mnt_table_parse_mountinfo(struct libmnt_table *tb, const char *filename,
-                          struct libmnt_table *u_tb)
+int mnt_table_merge_utab(struct libmnt_table *tb, struct libmnt_table *u_tb)
 {
        int rc = 0, priv_utab = 0;
-       int explicit_file = filename ? 1 : 0;
 
        assert(tb);
 
-       if (filename)
-               DBG_OBJ(TAB, tb, ul_debug("%s requested as mount table", filename));
-
-       if (!filename || strcmp(filename, _PATH_PROC_MOUNTINFO) == 0) {
-               filename = _PATH_PROC_MOUNTINFO;
-               tb->fmt = MNT_FMT_MOUNTINFO;
-               DBG_OBJ(TAB, tb, ul_debug("mountinfo parse: #1 read mountinfo"));
-       } else
-               tb->fmt = MNT_FMT_GUESS;
-
-       rc = mnt_table_parse_file(tb, filename);
-       if (rc) {
-               if (explicit_file)
-                       return rc;
-
-               /* hmm, old kernel? ...try /proc/mounts */
-               tb->fmt = MNT_FMT_MTAB;
-               return mnt_table_parse_file(tb, _PATH_PROC_MOUNTS);
-       }
-
-       if (!is_mountinfo(tb))
+       if (tb->nouseropts)
                return 0;
-       DBG_OBJ(TAB, tb, ul_debug("mountinfo parse: #2 read utab"));
-
        if (mnt_table_get_nents(tb) == 0)
-               return 0;                       /* empty, ignore utab */
-       /*
-        * try to read the user specific information from /run/mount/utabs
-        */
+               return 0;
+
        if (!u_tb) {
                const char *utab = mnt_get_utab_path();
 
@@ -1297,7 +1297,7 @@ int __mnt_table_parse_mountinfo(struct libmnt_table *tb, const char *filename,
                priv_utab = 1;
        }
 
-       DBG_OBJ(TAB, tb, ul_debug("mountinfo parse: #3 merge utab"));
+       DBG_OBJ(TAB, tb, ul_debug("merging utab"));
 
        if (rc == 0) {
                struct libmnt_fs *u_fs;
@@ -1305,16 +1305,52 @@ int __mnt_table_parse_mountinfo(struct libmnt_table *tb, const char *filename,
 
                mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
 
-               /*  merge user options into mountinfo from the kernel */
-               while(mnt_table_next_fs(u_tb, &itr, &u_fs) == 0)
+               while (mnt_table_next_fs(u_tb, &itr, &u_fs) == 0)
                        mnt_table_merge_user_fs(tb, u_fs);
        }
 
-
        if (priv_utab)
                mnt_unref_table(u_tb);
        return 0;
 }
+
+/* default filename is /proc/self/mountinfo
+ */
+int __mnt_table_parse_mountinfo(struct libmnt_table *tb, const char *filename,
+                          struct libmnt_table *u_tb)
+{
+       int rc = 0;
+       int explicit_file = filename ? 1 : 0;
+
+       assert(tb);
+
+       if (filename)
+               DBG_OBJ(TAB, tb, ul_debug("%s requested as mount table", filename));
+
+       if (!filename || strcmp(filename, _PATH_PROC_MOUNTINFO) == 0) {
+               filename = _PATH_PROC_MOUNTINFO;
+               tb->fmt = MNT_FMT_MOUNTINFO;
+               DBG_OBJ(TAB, tb, ul_debug("mountinfo parse: #1 read mountinfo"));
+       } else
+               tb->fmt = MNT_FMT_GUESS;
+
+       rc = mnt_table_parse_file(tb, filename);
+       if (rc) {
+               if (explicit_file)
+                       return rc;
+
+               /* hmm, old kernel? ...try /proc/mounts */
+               tb->fmt = MNT_FMT_MTAB;
+               return mnt_table_parse_file(tb, _PATH_PROC_MOUNTS);
+       }
+
+       if (!is_mountinfo(tb))
+               return 0;
+
+       DBG_OBJ(TAB, tb, ul_debug("mountinfo parse: #2 merge utab"));
+       return mnt_table_merge_utab(tb, u_tb);
+}
+
 /**
  * mnt_table_parse_mtab:
  * @tb: table
index c892bf2993c63ddab99fc20e6842c7bc13fd16f6..93c6192fce3381a5f94bc454d45cd8811ec0479b 100644 (file)
@@ -1108,6 +1108,7 @@ static struct libmnt_table *fetch_listmount(struct findmnt *findmnt)
        mnt_table_set_userdata(tb, findmnt);
 
        mnt_table_refer_statmnt(tb, sm);
+       mnt_table_disable_useropts(tb, 1);
 
        if (mnt_table_fetch_listmount(tb) != 0) {
                warn(_("failed to fetch mount nodes"));