From 39cd698282e51b3ce84aee72d7ff00063ae9a83f Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
Date: Tue, 1 Aug 2023 14:49:48 +0200
Subject: [PATCH] libmount: cleanup --fake mode

It was originally designed to play nasty games with /etc/mtab (mount
when /etc is read-only and update later when it's write-able).

The --fake is completely useless with the new API due to complexity
where we cannot skip any step, because the next stuff depends on it.
So, it makes more sense skip all functionality where libmount does
anything significant.

This commit add --fake check to hooks logic to skip all hooks as the
hooks are place where libmount implements mount related invasive
operations (create mountpoint, namespaces, create superblock, move,
mount, etc.).

Frankly, --fake without mtab is useless.

Fixes: https://github.com/util-linux/util-linux/issues/2395
Signed-off-by: Karel Zak <kzak@redhat.com>

Reference:https://github.com/util-linux/util-linux/commit/b42e4e2350a26b13a6165b78990e8814535ceb80
Conflict:NA
---
 libmount/src/context_mount.c     |  5 +++++
 libmount/src/hook_mount.c        |  7 -------
 libmount/src/hook_mount_legacy.c | 18 ------------------
 libmount/src/hooks.c             | 12 ++++++++++--
 sys-utils/mount.8.adoc           |  6 +++++-
 5 files changed, 20 insertions(+), 28 deletions(-)

diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
index d0da770..6ef6804 100644
--- a/libmount/src/context_mount.c
+++ b/libmount/src/context_mount.c
@@ -541,6 +541,11 @@ static int do_mount(struct libmnt_context *cxt, const char *try_type)
 	if (!rc)
 		rc = mnt_context_call_hooks(cxt, MNT_STAGE_MOUNT);
 
+	if (rc == 0 && mnt_context_is_fake(cxt)) {
+		DBG(CXT, ul_debugobj(cxt, "FAKE (-f) set status=0"));
+		cxt->syscall_status = 0;
+	}
+
 	if (org_type && rc != 0) {
 		__mnt_fs_set_fstype_ptr(cxt->fs, org_type);
 		org_type  = NULL;
diff --git a/libmount/src/hook_mount.c b/libmount/src/hook_mount.c
index 1597d62..ac50428 100644
--- a/libmount/src/hook_mount.c
+++ b/libmount/src/hook_mount.c
@@ -580,9 +580,6 @@ static int init_sysapi(struct libmnt_context *cxt,
 	if (!api)
 		return -ENOMEM;
 
-	if (mnt_context_is_fake(cxt))
-		goto fake;
-
 	if (path) {
 		api->fd_tree = open_mount_tree(cxt, path, flags);
 		if (api->fd_tree < 0)
@@ -615,10 +612,6 @@ static int init_sysapi(struct libmnt_context *cxt,
 fail:
 	DBG(HOOK, ul_debugobj(hs, "init fs/tree failed [errno=%d %m]", errno));
 	return -errno;
-fake:
-	DBG(CXT, ul_debugobj(cxt, " FAKE (-f)"));
-	cxt->syscall_status = 0;
-	return 0;
 }
 
 static int force_classic_mount(struct libmnt_context *cxt)
diff --git a/libmount/src/hook_mount_legacy.c b/libmount/src/hook_mount_legacy.c
index 2c07a01..7e62864 100644
--- a/libmount/src/hook_mount_legacy.c
+++ b/libmount/src/hook_mount_legacy.c
@@ -61,12 +61,6 @@ static int hook_propagation(struct libmnt_context *cxt,
 				hd->flags,
 				hd->flags & MS_REC ? " (recursive)" : ""));
 
-	if (mnt_context_is_fake(cxt)) {
-		DBG(CXT, ul_debugobj(cxt, "  FAKE (-f)"));
-		cxt->syscall_status = 0;
-		return 0;
-	}
-
 	/*
 	 * hd->flags are propagation flags as set in prepare_propagation()
 	 *
@@ -156,12 +150,6 @@ static int hook_bindremount(struct libmnt_context *cxt,
 				hd->flags,
 				hd->flags & MS_REC ? " (recursive)" : ""));
 
-	if (mnt_context_is_fake(cxt)) {
-		DBG(CXT, ul_debugobj(cxt, "  FAKE (-f)"));
-		cxt->syscall_status = 0;
-		return 0;
-	}
-
 	if (mnt_optlist_is_silent(cxt->optlist))
 		extra |= MS_SILENT;
 
@@ -251,12 +239,6 @@ static int hook_mount(struct libmnt_context *cxt,
 		options ? (cxt->flags & MNT_FL_MOUNTDATA) ? "binary" :
 			  options : "<none>"));
 
-	if (mnt_context_is_fake(cxt)) {
-		DBG(HOOK, ul_debugobj(hs, " FAKE (-f)"));
-		cxt->syscall_status = 0;
-		return 0;
-	}
-
 	if (mount(src, target, type, flags, options)) {
 		cxt->syscall_status = -errno;
 		cxt->syscall_name = "mount";
diff --git a/libmount/src/hooks.c b/libmount/src/hooks.c
index 88cf68d..2d79162 100644
--- a/libmount/src/hooks.c
+++ b/libmount/src/hooks.c
@@ -313,7 +313,12 @@ int mnt_context_has_hook(struct libmnt_context *cxt,
 
 static int call_hook(struct libmnt_context *cxt, struct hookset_hook *hook)
 {
-	int rc = hook->func(cxt, hook->hookset, hook->data);
+	int rc = 0;
+
+	if (mnt_context_is_fake(cxt))
+		DBG(CXT, ul_debugobj(cxt, " FAKE call"));
+	else
+		rc = hook->func(cxt, hook->hookset, hook->data);
 
 	hook->executed = 1;
 	if (!rc)
@@ -359,7 +364,10 @@ int mnt_context_call_hooks(struct libmnt_context *cxt, int stage)
 
 		DBG(CXT, ul_debugobj(cxt, "calling %s [first]", hs->name));
 
-		rc = hs->firstcall(cxt, hs, NULL);
+		if (mnt_context_is_fake(cxt))
+			DBG(CXT, ul_debugobj(cxt, " FAKE call"));
+		else
+			rc = hs->firstcall(cxt, hs, NULL);
 		if (!rc)
 			rc = call_depend_hooks(cxt, hs->name, stage);
 		if (rc < 0)
diff --git a/sys-utils/mount.8.adoc b/sys-utils/mount.8.adoc
index 60661d8..71e3723 100644
--- a/sys-utils/mount.8.adoc
+++ b/sys-utils/mount.8.adoc
@@ -325,7 +325,11 @@ Note that *mount* does not pass this option to the **/sbin/mount.**__type__ help
 (Used in conjunction with *-a*.) Fork off a new incarnation of *mount* for each device. This will do the mounts on different devices or different NFS servers in parallel. This has the advantage that it is faster; also NFS timeouts proceed in parallel. A disadvantage is that the order of the mount operations is undefined. Thus, you cannot use this option if you want to mount both _/usr_ and _/usr/spool_.
 
 *-f, --fake*::
-Causes everything to be done except for the actual system call; if it's not obvious, this "fakes" mounting the filesystem. This option is useful in conjunction with the *-v* flag to determine what the *mount* command is trying to do. It can also be used to add entries for devices that were mounted earlier with the *-n* option. The *-f* option checks for an existing record in _/etc/mtab_ and fails when the record already exists (with a regular non-fake mount, this check is done by the kernel).
+Causes everything to be done except for the mount-related system calls. The --fake option was originally designed to write an entry to /etc/mtab without actually mounting.
++
+The /etc/mtab is no longer maintained in userspace, and starting from version 2.39, the mount operation can be a complex chain of operations with dependencies between the syscalls. The --fake option forces libmount to skip all mount source preparation, mount option analysis, and the actual mounting process.
++
+The difference between fake and non-fake execution is huge. This is the reason why the --fake option has minimal significance for the current mount(8) implementation and it is maintained mostly for backward compatibility.
 
 *-i, --internal-only*::
 Don't call the **/sbin/mount.**__filesystem__ helper even if it exists.
-- 
2.33.0

