]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
umount: new --graceful option to exit successfully even if filesystem is unmounted
authorChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Fri, 20 Feb 2026 23:01:29 +0000 (18:01 -0500)
committerChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Mon, 23 Feb 2026 13:27:40 +0000 (08:27 -0500)
This new option makes it so that umount(8) exits successfully even
if the filesystem has already been unmounted or has no directory
entry. The usefulness of this behavior becomes apparent in cases
where idempotency is important, that is the focus lies in the
destruction of the mountpoint only.

Closes: #2132
Signed-off-by: Christian Goeschel Ndjomouo <cgoesc2@wgu.edu>
bash-completion/umount
sys-utils/umount.8.adoc
sys-utils/umount.c

index 9ea126bacf46859d886c5a10caea6e0af447ce1c..5aea50653ca216c9e1169727d7945bbd73f9dd45 100644 (file)
@@ -75,6 +75,7 @@ _umount_module()
                                --read-only
                                --types
                                --quiet
+                               --graceful
                                --verbose
                                --help
                                --version"
index f311eebdf08d7e23c59e0de06d300f142ad5a338..5fbc715e1b56cd73aea56ef201c253c83c935765 100644 (file)
@@ -100,6 +100,9 @@ Unmount only the filesystems that have the specified option set in _/etc/fstab_.
 *-q*, *--quiet*::
 Suppress "not mounted" error messages.
 
+*-g* *--graceful*::
+Exit successfully even if the filesystem has already been unmounted or does not exist.
+
 *-R*, *--recursive*::
 Recursively unmount each specified directory. Recursion for each directory will stop if any unmount operation in the chain fails for any reason. The relationship between mountpoints is determined by _/proc/self/mountinfo_ entries. The filesystem must be specified by mountpoint path; a recursive unmount by device name (or UUID) is unsupported. Since version 2.37 it umounts also all over-mounted filesystems (more filesystems on the same mountpoint).
 
index db2a4bee2f714d234d4bbee6959e6e82ec9e8bfe..3cdc200bf6d9252a6a60b4b91b7fa15807dea5d1 100644 (file)
@@ -42,6 +42,7 @@
 #include "optutils.h"
 
 static int quiet;
+static int graceful;
 static struct ul_env_list *envs_removed;
 
 static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)),
@@ -104,6 +105,8 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -v, --verbose           say what is being done\n"), out);
        fputs(_(" -q, --quiet             suppress 'not mounted' error messages\n"), out);
        fputs(_(" -N, --namespace <ns>    perform umount in another namespace\n"), out);
+       fputs(_(" -g, --graceful          don't return an error when the mountpoint has already\n"
+               "                           been unmounted or the directory does not exist\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
        fprintf(out, USAGE_HELP_OPTIONS(25));
@@ -160,6 +163,11 @@ static int mk_exit_code(struct libmnt_context *cxt, int api_rc)
        int rc;
 
        rc = mnt_context_get_excode(cxt, api_rc, buf, sizeof(buf));
+       /* exit succesfully even if the filesystem has already been unmounted or does not exist */
+       if (graceful && rc == MNT_EX_FAIL && mnt_context_syscall_called(cxt)
+                               && (mnt_context_get_syscall_errno(cxt) == EINVAL
+                               || mnt_context_get_syscall_errno(cxt) == ENOENT))
+               return MNT_EX_SUCCESS;
 
        /* suppress "not mounted" error message */
        if (quiet) {
@@ -496,6 +504,7 @@ int main(int argc, char **argv)
                { "verbose",         no_argument,       NULL, 'v'             },
                { "version",         no_argument,       NULL, 'V'             },
                { "namespace",       required_argument, NULL, 'N'             },
+               { "graceful",        no_argument,       NULL, 'g'             },
                { NULL, 0, NULL, 0 }
        };
 
@@ -521,7 +530,7 @@ int main(int argc, char **argv)
 
        mnt_context_set_tables_errcb(cxt, table_parser_errcb);
 
-       while ((c = getopt_long(argc, argv, "aAcdfhilnqRrO:t:vVN:",
+       while ((c = getopt_long(argc, argv, "aAcdfghilnqRrO:t:vVN:",
                                        longopts, NULL)) != -1) {
 
 
@@ -599,7 +608,9 @@ int main(int argc, char **argv)
                                err(MNT_EX_SYSERR, _("failed to set target namespace to %s"), pid ? path : optarg);
                        break;
                }
-
+               case 'g':
+                       graceful = 1;
+                       break;
                case 'h':
                        mnt_free_context(cxt);
                        usage();