mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
statmount: add flag to retrieve unescaped options
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 <mszeredi@redhat.com> Link: https://lore.kernel.org/r/20241112101006.30715-1-mszeredi@redhat.com Acked-by: Jeff Layton <jlayton@kernel.org> [brauner: tweak variable naming and parsing add example output] Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
39bb1bf0b4
commit
2f4d4503e9
2 changed files with 51 additions and 3 deletions
|
@ -5072,6 +5072,43 @@ static int statmount_mnt_opts(struct kstatmount *s, struct seq_file *seq)
|
||||||
return 0;
|
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)
|
static int statmount_string(struct kstatmount *s, u64 flag)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -5097,6 +5134,10 @@ static int statmount_string(struct kstatmount *s, u64 flag)
|
||||||
sm->mnt_opts = start;
|
sm->mnt_opts = start;
|
||||||
ret = statmount_mnt_opts(s, seq);
|
ret = statmount_mnt_opts(s, seq);
|
||||||
break;
|
break;
|
||||||
|
case STATMOUNT_OPT_ARRAY:
|
||||||
|
sm->opt_array = start;
|
||||||
|
ret = statmount_opt_array(s, seq);
|
||||||
|
break;
|
||||||
case STATMOUNT_FS_SUBTYPE:
|
case STATMOUNT_FS_SUBTYPE:
|
||||||
sm->fs_subtype = start;
|
sm->fs_subtype = start;
|
||||||
statmount_fs_subtype(s, seq);
|
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)
|
if (!err && s->mask & STATMOUNT_MNT_OPTS)
|
||||||
err = statmount_string(s, 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)
|
if (!err && s->mask & STATMOUNT_FS_SUBTYPE)
|
||||||
err = statmount_string(s, 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 | \
|
#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
|
||||||
STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS | \
|
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,
|
static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
|
||||||
struct statmount __user *buf, size_t bufsize,
|
struct statmount __user *buf, size_t bufsize,
|
||||||
|
|
|
@ -154,7 +154,7 @@ struct mount_attr {
|
||||||
*/
|
*/
|
||||||
struct statmount {
|
struct statmount {
|
||||||
__u32 size; /* Total size, including strings */
|
__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 */
|
__u64 mask; /* What results were written */
|
||||||
__u32 sb_dev_major; /* Device ID */
|
__u32 sb_dev_major; /* Device ID */
|
||||||
__u32 sb_dev_minor;
|
__u32 sb_dev_minor;
|
||||||
|
@ -175,7 +175,9 @@ struct statmount {
|
||||||
__u64 mnt_ns_id; /* ID of the mount namespace */
|
__u64 mnt_ns_id; /* ID of the mount namespace */
|
||||||
__u32 fs_subtype; /* [str] Subtype of fs_type (if any) */
|
__u32 fs_subtype; /* [str] Subtype of fs_type (if any) */
|
||||||
__u32 sb_source; /* [str] Source string of the mount */
|
__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 */
|
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_MNT_OPTS 0x00000080U /* Want/got mnt_opts */
|
||||||
#define STATMOUNT_FS_SUBTYPE 0x00000100U /* Want/got fs_subtype */
|
#define STATMOUNT_FS_SUBTYPE 0x00000100U /* Want/got fs_subtype */
|
||||||
#define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */
|
#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
|
* Special @mnt_id values that can be passed to listmount
|
||||||
|
|
Loading…
Add table
Reference in a new issue