aboutsummaryrefslogtreecommitdiffstats
path: root/libmount/src
diff options
context:
space:
mode:
authorKarel Zak <kzak@redhat.com>2024-09-19 11:13:22 +0200
committerKarel Zak <kzak@redhat.com>2024-09-24 12:40:19 +0200
commita904aefe307359700dc64e3ad524baa6ee19e82a (patch)
tree5d6d0eaf4f7e22a1035da741884ada2055886ea2 /libmount/src
parent466ed6db5fb7e976cae8e0ab8fd45dc505070e99 (diff)
downloadutil-linux-a904aefe307359700dc64e3ad524baa6ee19e82a.tar.gz
libmount: add X-mount.nocanonicalize[=source|target]
The new kernel mount API can bind-mount over a symlink. However, this feature does not work with libmount because it canonicalizes all paths by default. A possible workaround is to use the --no-canonicalize option on the mount(8) command line, but this is a heavy-handed solution as it disables all conversions for all paths and tags (such as LABEL=) and fstab processing. This commit introduces the X-mount.nocanonicalize userspace mount option to control canonicalization. It only affects paths used for mounting and does not affect tags and searching in fstab. Additionally, this setting possible to use in fstab. If the optional argument [=source|target] is not specified, then paths canonicalization is disabled for both the source and target paths. Adresses: https://github.com/util-linux/util-linux/issues/2370 Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libmount/src')
-rw-r--r--libmount/src/context.c37
-rw-r--r--libmount/src/context_mount.c2
-rw-r--r--libmount/src/mountP.h2
3 files changed, 38 insertions, 3 deletions
diff --git a/libmount/src/context.c b/libmount/src/context.c
index a9cb4ef26c..28cce65e83 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -506,13 +506,45 @@ int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable)
* mnt_context_is_nocanonicalize:
* @cxt: mount context
*
- * Returns: 1 if no-canonicalize mode is enabled or 0.
+ * Returns: 1 if no-canonicalize mode (on [u]mount command line) is enabled or 0.
*/
int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
{
return cxt->flags & MNT_FL_NOCANONICALIZE ? 1 : 0;
}
+
+/*
+ * Returns 1 if "x-mount.nocanonicalize[=<type>]" userspace mount option is
+ * specified. The optional arguments 'type' should be "source" or "target".
+ */
+int mnt_context_is_xnocanonicalize(
+ struct libmnt_context *cxt,
+ const char *type)
+{
+ struct libmnt_optlist *ol;
+ struct libmnt_opt *opt;
+ const char *arg;
+
+ assert(cxt);
+ assert(type);
+
+ if (mnt_context_is_nocanonicalize(cxt))
+ return 1;
+
+ ol = mnt_context_get_optlist(cxt);
+ if (!ol)
+ return 0;
+ opt = mnt_optlist_get_named(ol, "X-mount.nocanonicalize",
+ cxt->map_userspace);
+ if (!opt)
+ return 0;
+ arg = mnt_opt_get_value(opt);
+ if (!arg)
+ return 1;
+ return strcmp(arg, type) == 0;
+}
+
/**
* mnt_context_enable_lazy:
* @cxt: mount context
@@ -1884,7 +1916,8 @@ int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
rc = path ? mnt_fs_set_source(cxt->fs, path) : -MNT_ERR_NOSOURCE;
- } else if (cache && !mnt_fs_is_pseudofs(cxt->fs)) {
+ } else if (cache && !mnt_fs_is_pseudofs(cxt->fs)
+ && !mnt_context_is_xnocanonicalize(cxt, "source")) {
/*
* Source is PATH (canonicalize)
*/
diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
index e42c8705e2..599370782f 100644
--- a/libmount/src/context_mount.c
+++ b/libmount/src/context_mount.c
@@ -726,7 +726,7 @@ static int prepare_target(struct libmnt_context *cxt)
return -MNT_ERR_NAMESPACE;
/* canonicalize the path */
- if (rc == 0) {
+ if (rc == 0 && !mnt_context_is_xnocanonicalize(cxt, "target")) {
struct libmnt_cache *cache = mnt_context_get_cache(cxt);
if (cache) {
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index ed5f2ec29f..2c1f62a8ff 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -654,6 +654,8 @@ extern int mnt_context_apply_fs(struct libmnt_context *cxt, struct libmnt_fs *fs
extern struct libmnt_optlist *mnt_context_get_optlist(struct libmnt_context *cxt);
+extern int mnt_context_is_xnocanonicalize(struct libmnt_context *cxt, const char *type);
+
/* tab_update.c */
extern int mnt_update_emit_event(struct libmnt_update *upd);
extern int mnt_update_set_filename(struct libmnt_update *upd, const char *filename);