]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: add X-mount.nocanonicalize[=source|target]
authorKarel Zak <kzak@redhat.com>
Thu, 19 Sep 2024 09:13:22 +0000 (11:13 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 24 Sep 2024 10:40:19 +0000 (12:40 +0200)
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>
libmount/src/context.c
libmount/src/context_mount.c
libmount/src/mountP.h
sys-utils/mount.8.adoc

index a9cb4ef26cbeff3f23cf5a82c66a715f9e75c477..28cce65e8341e55380db02bc8257f4733393bae8 100644 (file)
@@ -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)
                 */
index e42c8705e2b87028b9b58daa0c5032c444552376..599370782fa6fe774c90a9b73162c07b0b1fad7c 100644 (file)
@@ -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) {
index ed5f2ec29f2bb40e9ae2b78cfb8bb5c0f10e92e7..2c1f62a8fff297431ed88e87709254345004265d 100644 (file)
@@ -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);
index 4c9bef6f4f0f870886c019e721d6938a81261151..28a84a86c24afdee16d6691c17bb4c53b6b1e09e 100644 (file)
@@ -319,7 +319,7 @@ Note that it is a bad practice to use *mount -a* for _fstab_ checking. The recom
 Remount a subtree somewhere else (so that its contents are available in both places). See above, under *Bind mount operation*.
 
 *-c*, *--no-canonicalize*::
-Don't canonicalize paths. The *mount* command canonicalizes all paths (from the command line or _fstab_) by default. This option can be used together with the *-f* flag for already canonicalized absolute paths. The option is designed for mount helpers which call *mount -i*. It is strongly recommended to not use this command-line option for normal mount operations.
+Do not canonicalize any paths or tags during the mount process. The *mount* command automatically canonicalizes all paths (from the command line or _fstab_). This option can be used in conjunction with the *-f* flag for paths that are already canonicalized. This option is intended for mount helpers that call *mount -i*. It is highly recommended to not use this command-line option for regular mount operations. See also the X-mount.nocanonicalize mount options.
 +
 Note that *mount* does not pass this option to the **/sbin/mount.**__type__ helpers.
 
@@ -714,6 +714,13 @@ ____
 *X-mount.mkdir*[=_mode_]::
 Allow to make a target directory (mountpoint) if it does not exist yet. The optional argument _mode_ specifies the filesystem access mode used for *mkdir*(2) in octal notation. The default mode is 0755. This functionality is supported only for root users or when *mount* is executed without suid permissions. The option is also supported as *x-mount.mkdir*, but this notation is deprecated since v2.30. See also *--mkdir* command line option.
 
+*X-mount.nocanonicalize*[=_type_]::
+Allows disabling of canonicalization for mount source and target paths. By default, the `mount` command resolves all paths to their absolute paths without symlinks. However, this behavior may not be desired in certain situations, such as when bind-mounting over a symlink. The optional argument _type_ can be either "source" or "target" (mountpoint). If no _type_ is specified, then canonicalization is disabled for both types. This mount option does not affect the conversion of source tags (e.g. LABEL= or UUID=) and fstab processing.
++
+The command line option *--no-canonicalize* overrides this mount option and affects all path and tag conversions in all situations.
++
+Note that *mount*(8) still sanitizes and canonicalizes the source and target paths specified on the command line by non-root users, regardless of the X-mount.nocanonicalize setting.
+
 **X-mount.subdir=**__directory__::
 Allow mounting sub-directory from a filesystem instead of the root directory. For now, this feature is implemented by temporary filesystem root directory mount in unshared namespace and then bind the sub-directory to the final mount point and umount the root of the filesystem. The sub-directory mount shows up atomically for the rest of the system although it is implemented by multiple *mount*(2) syscalls.
 +