]> Git Repo - J-linux.git/commitdiff
statmount: add flag to retrieve unescaped options
authorMiklos Szeredi <[email protected]>
Tue, 12 Nov 2024 10:10:04 +0000 (11:10 +0100)
committerChristian Brauner <[email protected]>
Wed, 13 Nov 2024 16:27:02 +0000 (17:27 +0100)
Filesystem options can be retrieved with STATMOUNT_MNT_OPTS, which
returns a string of comma separated options, where some characters are
escaped using the \OOO notation.

Add a new flag, STATMOUNT_OPT_ARRAY, which instead returns the raw
option values separated with '\0' charaters.

Since escaped charaters are rare, this inteface is preferable for
non-libmount users which likley don't want to deal with option
de-escaping.

Example code:

if (st->mask & STATMOUNT_OPT_ARRAY) {
const char *opt = st->str + st->opt_array;

for (unsigned int i = 0; i < st->opt_num; i++) {
printf("opt_array[%i]: <%s>\n", i, opt);
opt += strlen(opt) + 1;
}
}

Example ouput:

(1) mnt_opts: <lowerdir+=/l\054w\054r,lowerdir+=/l\054w\054r1,upperdir=/upp\054r,workdir=/w\054rk,redirect_dir=nofollow,uuid=null>

(2) opt_array[0]: <lowerdir+=/l,w,r>
    opt_array[1]: <lowerdir+=/l,w,r1>
    opt_array[2]: <upperdir=/upp,r>
    opt_array[3]: <workdir=/w,rk>
    opt_array[4]: <redirect_dir=nofollow>
    opt_array[5]: <uuid=null>

Signed-off-by: Miklos Szeredi <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Acked-by: Jeff Layton <[email protected]>
[brauner: tweak variable naming and parsing add example output]
Signed-off-by: Christian Brauner <[email protected]>
fs/namespace.c
include/uapi/linux/mount.h

index d32b5afa99dcfb9176668bfe3e14a57264ce710e..4f39c4aba85dd37e9e52094c4376d7a332c22469 100644 (file)
@@ -5072,6 +5072,43 @@ static int statmount_mnt_opts(struct kstatmount *s, struct seq_file *seq)
        return 0;
 }
 
+static int statmount_opt_array(struct kstatmount *s, struct seq_file *seq)
+{
+       struct vfsmount *mnt = s->mnt;
+       struct super_block *sb = mnt->mnt_sb;
+       size_t start = seq->count;
+       char *buf_start, *buf_end, *opt_start, *opt_end;
+       u32 count = 0;
+       int err;
+
+       if (!sb->s_op->show_options)
+               return 0;
+
+       buf_start = seq->buf + start;
+       err = sb->s_op->show_options(seq, mnt->mnt_root);
+       if (err)
+               return err;
+
+       if (unlikely(seq_has_overflowed(seq)))
+               return -EAGAIN;
+
+       if (seq->count == start)
+               return 0;
+
+       buf_end = seq->buf + seq->count;
+       *buf_end = '\0';
+       for (opt_start = buf_start + 1; opt_start < buf_end; opt_start = opt_end + 1) {
+               opt_end = strchrnul(opt_start, ',');
+               *opt_end = '\0';
+               buf_start += string_unescape(opt_start, buf_start, 0, UNESCAPE_OCTAL) + 1;
+               if (WARN_ON_ONCE(++count == 0))
+                       return -EOVERFLOW;
+       }
+       seq->count = buf_start - 1 - seq->buf;
+       s->sm.opt_num = count;
+       return 0;
+}
+
 static int statmount_string(struct kstatmount *s, u64 flag)
 {
        int ret = 0;
@@ -5097,6 +5134,10 @@ static int statmount_string(struct kstatmount *s, u64 flag)
                sm->mnt_opts = start;
                ret = statmount_mnt_opts(s, seq);
                break;
+       case STATMOUNT_OPT_ARRAY:
+               sm->opt_array = start;
+               ret = statmount_opt_array(s, seq);
+               break;
        case STATMOUNT_FS_SUBTYPE:
                sm->fs_subtype = start;
                statmount_fs_subtype(s, seq);
@@ -5250,6 +5291,9 @@ static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,
        if (!err && s->mask & STATMOUNT_MNT_OPTS)
                err = statmount_string(s, STATMOUNT_MNT_OPTS);
 
+       if (!err && s->mask & STATMOUNT_OPT_ARRAY)
+               err = statmount_string(s, STATMOUNT_OPT_ARRAY);
+
        if (!err && s->mask & STATMOUNT_FS_SUBTYPE)
                err = statmount_string(s, STATMOUNT_FS_SUBTYPE);
 
@@ -5278,7 +5322,8 @@ static inline bool retry_statmount(const long ret, size_t *seq_size)
 
 #define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
                              STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS | \
-                             STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE)
+                             STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE | \
+                             STATMOUNT_OPT_ARRAY)
 
 static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
                              struct statmount __user *buf, size_t bufsize,
index 2b49e9131d77165899d8e3c17366c6afaa8b7795..c0fda4604187d21ba8d4da2ad9bbc0524fe35536 100644 (file)
@@ -154,7 +154,7 @@ struct mount_attr {
  */
 struct statmount {
        __u32 size;             /* Total size, including strings */
-       __u32 mnt_opts;         /* [str] Mount options of the mount */
+       __u32 mnt_opts;         /* [str] Options (comma separated, escaped) */
        __u64 mask;             /* What results were written */
        __u32 sb_dev_major;     /* Device ID */
        __u32 sb_dev_minor;
@@ -175,7 +175,9 @@ struct statmount {
        __u64 mnt_ns_id;        /* ID of the mount namespace */
        __u32 fs_subtype;       /* [str] Subtype of fs_type (if any) */
        __u32 sb_source;        /* [str] Source string of the mount */
-       __u64 __spare2[48];
+       __u32 opt_num;          /* Number of fs options */
+       __u32 opt_array;        /* [str] Array of nul terminated fs options */
+       __u64 __spare2[47];
        char str[];             /* Variable size part containing strings */
 };
 
@@ -211,6 +213,7 @@ struct mnt_id_req {
 #define STATMOUNT_MNT_OPTS             0x00000080U     /* Want/got mnt_opts */
 #define STATMOUNT_FS_SUBTYPE           0x00000100U     /* Want/got fs_subtype */
 #define STATMOUNT_SB_SOURCE            0x00000200U     /* Want/got sb_source */
+#define STATMOUNT_OPT_ARRAY            0x00000400U     /* Want/got opt_... */
 
 /*
  * Special @mnt_id values that can be passed to listmount
This page took 0.072752 seconds and 4 git commands to generate.