]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
mountpoint: add --show option to print mountpoint path
authorKarel Zak <kzak@redhat.com>
Wed, 19 Nov 2025 12:32:25 +0000 (13:32 +0100)
committerKarel Zak <kzak@redhat.com>
Thu, 20 Nov 2025 10:29:22 +0000 (11:29 +0100)
Add a new --show option that prints the actual mountpoint path for
a given directory or file. This is useful for:
- Resolving any path to its containing mountpoint
- Finding the canonical mountpoint path when symlinks are involved
- Determining the mountpoint from paths within filesystems

The option requires kernel support for statmount(2) (Linux 6.8+).
On older kernels without statmount support, the option fails with
an error message, as the /proc/self/mountinfo fallback cannot
resolve arbitrary paths to their containing mountpoint.

Example usage:
  $ mountpoint --show /
  /
  $ mountpoint --show /home/user/file.txt
  /home

The --show option always returns EXIT_SUCCESS (0) when it successfully
finds the mountpoint, regardless of whether the given path itself is
a mountpoint or not.

Addresses: https://github.com/util-linux/util-linux/issues/3806
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/mountpoint.1.adoc
sys-utils/mountpoint.c

index 0e1252c72c91769910936caef461497f32a6827f..250f6d1a95418b627b0380b213bc03a51e0a2a17 100644 (file)
@@ -34,6 +34,9 @@ Do not follow symbolic link if it the last element of the _directory_ path.
 *-x*, *--devno*::
 Show the major/minor numbers of the given blockdevice on standard output.
 
+*--show*::
+Print the mountpoint path for the given path. This resolves the given directory or file to its actual mountpoint, which is useful with bind mounts, symlinks, or paths within filesystems. This option requires kernel support for the *statmount*(2) system call (Linux 6.8 and newer). On older kernels, this option will fail with an error message.
+
 include::man-common/help-version.adoc[]
 
 == EXIT STATUS
index 8a114b5bb068f76026d64e78048dba4af6e278f0..aed1f0fef699ccdd35051fc4cfb41ee3e4f23931 100644 (file)
 
 struct mountpoint_control {
        char *path;
+       char *mnt_target;
        dev_t dev;
        struct stat st;
        bool    dev_devno,
                fs_devno,
                nofollow,
-               quiet;
+               quiet,
+               show;
 };
 
 #ifdef HAVE_STATMOUNT_API
@@ -84,6 +86,9 @@ static int dir_to_device_statmount(struct mountpoint_control *ctl)
                goto done;
        }
 
+       if (ctl->show)
+               ctl->mnt_target = xstrdup(mnt_target);
+
        if (strcmp(mnt_target, cn ? cn : ctl->path) != 0)
                rc = 1; /* not a mountpoint */
        else {
@@ -118,6 +123,9 @@ static int dir_to_device(struct mountpoint_control *ctl)
        /*
         * Fallback for older kernels without statmount() support
         */
+       if (ctl->show)
+               errx(EXIT_FAILURE, _("--show is not supported on this system"));
+
        tb = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
        if (!tb) {
                /*
@@ -190,7 +198,8 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -q, --quiet        quiet mode - don't print anything\n"
                "     --nofollow     do not follow symlink\n"
                " -d, --fs-devno     print maj:min device number of the filesystem\n"
-               " -x, --devno        print maj:min device number of the block device\n"), out);
+               " -x, --devno        print maj:min device number of the block device\n"
+               "     --show         print mountpoint for given path\n"), out);
        fputs(USAGE_SEPARATOR, out);
        fprintf(out, USAGE_HELP_OPTIONS(20));
        fprintf(out, USAGE_MAN_TAIL("mountpoint(1)"));
@@ -204,7 +213,8 @@ int main(int argc, char **argv)
        struct mountpoint_control ctl = { NULL };
 
        enum {
-               OPT_NOFOLLOW = CHAR_MAX + 1
+               OPT_NOFOLLOW = CHAR_MAX + 1,
+               OPT_SHOW
        };
 
        static const struct option longopts[] = {
@@ -212,6 +222,7 @@ int main(int argc, char **argv)
                { "nofollow", no_argument, NULL, OPT_NOFOLLOW },
                { "fs-devno", no_argument, NULL, 'd' },
                { "devno",    no_argument, NULL, 'x' },
+               { "show",     no_argument, NULL, OPT_SHOW },
                { "help",     no_argument, NULL, 'h' },
                { "version",  no_argument, NULL, 'V' },
                { NULL, 0, NULL, 0 }
@@ -239,6 +250,9 @@ int main(int argc, char **argv)
                case 'x':
                        ctl.dev_devno = 1;
                        break;
+               case OPT_SHOW:
+                       ctl.show = 1;
+                       break;
 
                case 'h':
                        usage();
@@ -281,6 +295,13 @@ int main(int argc, char **argv)
                }
                return EXIT_FAILURE;
        }
+
+       if (ctl.show) {
+               printf("%s\n", ctl.mnt_target);
+               free(ctl.mnt_target);
+               return EXIT_SUCCESS;
+       }
+
        if (rc == 1) {
                if (!ctl.quiet)
                        printf(_("%s is not a mountpoint\n"), ctl.path);