Re: [PATCH] find: make -mount POSIX 2024 compliant
Bernhard Voelker <[email protected]> Fri, 2 Jan 2026 23:00:01 +0100
| Newsgroups | gmane.comp.gnu.findutils.bugs,gmane.comp.gnu.findutils.patches |
|---|---|
| Message-ID | <[email protected]> |
On 12/28/25 15:01, Bernhard Voelker wrote: > On 12/5/25 16:24, Lukáš Zaoral wrote: >> + The -mount option is now POSIX compliant. [...] > > This is not quite true [...] * [PATCH 1/4] find: make -mount POSIX 2024 compliant I've pushed your patch with the minor tweak ... - The -mount option is now POSIX compliant. [...] + The -mount option is now POSIX 2024 compliant. [...] ... and pushed the following on top to improve the NEWS and to add regular and check-root tests: * [PATCH 2/4] NEWS: enhance description about the -mount change * [PATCH 3/4] find: add -mount tests * [PATCH 4/4] find: add more -mount tests (check-root) > As the change is quite delicate, I'd like to add some follow-up commits to clarify > the new -mount behavior vs. -xdev in the documentation as well. I'm still on this one ... Have a nice day, Berny
0001-find-make-mount-POSIX-2024-compliant.patch
(text/x-patch, 7 KB)
From cd8568758a108ef0e6e1905ce540cd2ade3da796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zaoral?= <[email protected]> Date: Sun, 28 Dec 2025 14:53:41 +0100 Subject: [PATCH 1/4] find: make -mount POSIX 2024 compliant * find/defs.h (struct options): Add mount member and rename stay_on_filesystem to xdev. * find/ftsfind.c (find): Set FTS_MOUNT flag when -mount is enabled. * find/parser.c (parse_table): Use a separate parser for -mount. (parse_mount): Declare and define function. (parse_xdev): Use xdev option flag. * find/util.c (set_option_defaults): Initialize new struct members. * doc/find.texi (node Filesystems): Add new section describing the new behaviour of -mount and specify the current behaviour of -xdev. * find/find.1: Document the new -mount behaviour and specify current behaviour of -xdev. * NEWS (Changes in find): Mention the -mount behaviour change. --- NEWS | 3 +++ doc/find.texi | 8 +++++--- find/defs.h | 7 +++++-- find/find.1 | 10 ++++------ find/ftsfind.c | 5 ++++- find/parser.c | 12 ++++++++++-- find/util.c | 2 +- 7 files changed, 32 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index 549f6d4c..5ce613c1 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,9 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout) are passed with a leading dash, e.g. '-!'. Future releases will not accept that any more. Accepting that was rather a bug "since the beginning". + The -mount option is now POSIX 2024 compliant. Find will ignore files on + different devices as opposed to being a mere alias for -xdev. [#54745] + ** Documentation Changes The forthcoming Issue 8 of the POSIX standard will standardise "find diff --git a/doc/find.texi b/doc/find.texi index 4852a5a1..192f7dea 100644 --- a/doc/find.texi +++ b/doc/find.texi @@ -1624,10 +1624,12 @@ them. There are two ways to avoid searching certain filesystems. One way is to tell @code{find} to only search one filesystem: +@deffn Option -mount +Ignore files on other devices. +@end deffn + @deffn Option -xdev -@deffnx Option -mount -Don't descend directories on other filesystems. These options are -synonyms. +Don't descend into directories on other devices. @end deffn The other way is to check the type of filesystem each file is on, and diff --git a/find/defs.h b/find/defs.h index ea3e5cab..f1c8d706 100644 --- a/find/defs.h +++ b/find/defs.h @@ -549,8 +549,11 @@ struct options are non-directories. */ bool no_leaf_check; + /* If true, skip files on other devices. */ + bool mount; + /* If true, don't cross filesystem boundaries. */ - bool stay_on_filesystem; + bool xdev; /* If true, we ignore the problem where we find that a directory entry * no longer exists by the time we get around to processing it. @@ -648,7 +651,7 @@ struct state int starting_path_length; /* If true, don't descend past current directory. - Can be set by -prune, -maxdepth, and -xdev/-mount. */ + Can be set by -prune, -maxdepth, -mount and -xdev. */ bool stop_at_current_level; /* Status value to return to system. */ diff --git a/find/find.1 b/find/find.1 index 88591d69..e5868272 100644 --- a/find/find.1 +++ b/find/find.1 @@ -630,10 +630,7 @@ non-negative integer). Using means process all files except the starting-points. .IP \-mount -Don't descend directories on other filesystems. An alternate name for -.BR \-xdev , -for compatibility with some other versions of -.BR find . +Ignore files on other devices. .IP \-noignore_readdir_race Turns off the effect of @@ -659,7 +656,7 @@ to stat them; this gives a significant increase in search speed. Print the \fBfind\fR version number and exit. .IP \-xdev -Don't descend directories on other filesystems. +Don't descend into directories on other devices. .SS TESTS Some tests, for example @@ -1989,7 +1986,7 @@ For closest compliance to the POSIX standard, you should set the .B POSIXLY_CORRECT environment variable. The following options are specified in the POSIX standard -(IEEE Std 1003.1-2008, 2016 Edition): +(IEEE Std 1003.1-2024 Edition): .IP \fB\-H\fR This option is supported. @@ -2053,6 +2050,7 @@ The primaries .BR \-exec , .BR \-group , .BR \-links , +.BR \-mount , .BR \-mtime , .BR \-nogroup , .BR \-nouser , diff --git a/find/ftsfind.c b/find/ftsfind.c index 5709b1db..17cfb1d1 100644 --- a/find/ftsfind.c +++ b/find/ftsfind.c @@ -480,7 +480,10 @@ find (char *arg) break; } - if (options.stay_on_filesystem) + if (options.mount) + ftsoptions |= FTS_MOUNT; + + if (options.xdev) ftsoptions |= FTS_XDEV; p = fts_open (arglist, ftsoptions, nullptr); diff --git a/find/parser.c b/find/parser.c index f740b06d..52df3577 100644 --- a/find/parser.c +++ b/find/parser.c @@ -122,6 +122,7 @@ static bool parse_ls (const struct parser_table*, char *argv[], int * static bool parse_maxdepth (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_mindepth (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_mmin (const struct parser_table*, char *argv[], int *arg_ptr); +static bool parse_mount (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_name (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_negate (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_newer (const struct parser_table*, char *argv[], int *arg_ptr); @@ -214,7 +215,7 @@ static struct parser_table const parse_table[] = { ARG_OPTION, "ignore_readdir_race", parse_ignore_race, nullptr }, /* GNU */ { ARG_OPTION, "maxdepth", parse_maxdepth, nullptr }, /* GNU */ { ARG_OPTION, "mindepth", parse_mindepth, nullptr }, /* GNU */ - { ARG_OPTION, "mount", parse_xdev, nullptr }, /* Unix */ + { ARG_OPTION, "mount", parse_mount, nullptr }, /* POSIX */ { ARG_OPTION, "noleaf", parse_noleaf, nullptr }, /* GNU */ { ARG_OPTION, "noignore_readdir_race", parse_noignore_race, nullptr }, /* GNU */ { ARG_OPTION, "xdev", parse_xdev, nullptr }, /* POSIX */ @@ -2476,10 +2477,17 @@ parse_context (const struct parser_table* entry, char **argv, int *arg_ptr) return true; } +static bool +parse_mount (const struct parser_table* entry, char **argv, int *arg_ptr) +{ + options.mount = true; + return parse_noop (entry, argv, arg_ptr); +} + static bool parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr) { - options.stay_on_filesystem = true; + options.xdev = true; return parse_noop (entry, argv, arg_ptr); } diff --git a/find/util.c b/find/util.c index 2e8fbc1e..509a6c2c 100644 --- a/find/util.c +++ b/find/util.c @@ -1010,7 +1010,7 @@ set_option_defaults (struct options *p) p->cur_day_start.tv_nsec = p->start_time.tv_nsec; p->full_days = false; - p->stay_on_filesystem = false; + p->mount = p->xdev = false; p->ignore_readdir_race = false; if (p->posixly_correct) -- 2.52.0
0002-NEWS-enhance-description-about-the-mount-change.patch
(text/x-patch, 2 KB)
From 6da3a73f73eb01efe0511c2643e66bb2f980b642 Mon Sep 17 00:00:00 2001 From: Bernhard Voelker <[email protected]> Date: Thu, 1 Jan 2026 20:25:56 +0100 Subject: [PATCH 2/4] NEWS: enhance description about the -mount change * NEWS (Changes in find): Clarify better what is the difference between the -mount and -xdev options including an example. Also move the topic to the top of the section due to its importance. --- NEWS | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 5ce613c1..d4002688 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,17 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout) ** Changes in find + As announced since the release of 4.7.0 (2019) and mandated by POSIX 2024, + the behaviour of the -mount option changed: while it was a mere alias for + the -xdev option to prevent descending into directories of another device, + the -mount option now makes find(1) ignore files on another device, i.e., + 'find -mount' will skip the entry of active mount points already. + Example, assuming the PROC filesystem is mounted on '/proc': + $ find / -mount -path /proc -print + $ find / -xdev -path /proc -print + /proc + [#54745] + The actions -execdir and -okdir now refuse the '{}' replacement in the zeroth argument of the command to be run. While POSIX allows this for -exec, this is deemed insecure as an attacker could influence which files could be found. @@ -28,9 +39,6 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout) are passed with a leading dash, e.g. '-!'. Future releases will not accept that any more. Accepting that was rather a bug "since the beginning". - The -mount option is now POSIX 2024 compliant. Find will ignore files on - different devices as opposed to being a mere alias for -xdev. [#54745] - ** Documentation Changes The forthcoming Issue 8 of the POSIX standard will standardise "find -- 2.52.0
0003-find-add-mount-tests.patch
(text/x-patch, 2.9 KB)
From 0d8de8729964a93741888d3316c589790debdbc3 Mon Sep 17 00:00:00 2001 From: Bernhard Voelker <[email protected]> Date: Sun, 28 Dec 2025 16:07:03 +0100 Subject: [PATCH 3/4] find: add -mount tests * tests/find/mount-vs-xdev.sh: Add test. * tests/local.mk (sh_tests): Reference it. --- tests/find/mount-vs-xdev.sh | 59 +++++++++++++++++++++++++++++++++++++ tests/local.mk | 1 + 2 files changed, 60 insertions(+) create mode 100755 tests/find/mount-vs-xdev.sh diff --git a/tests/find/mount-vs-xdev.sh b/tests/find/mount-vs-xdev.sh new file mode 100755 index 00000000..9007a81e --- /dev/null +++ b/tests/find/mount-vs-xdev.sh @@ -0,0 +1,59 @@ +#!/bin/sh +# Exercise find -mount vs. -xdev behaviour. + +# Copyright (C) 2026 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; fu_path_prepend_ +print_ver_ find + +getmntpoint () { + # Skip header line and print last field. + df "$1" | awk 'NR==2 {print $NF}' +} + +mnt_root=$( getmntpoint '/' ) \ + && test "$mnt_root" \ + || framework_failure_ + +found=0 +# Find a directory entry which is mounted (likely) from a different device +# than the '/' directory. +for m in /dev /home /proc /run /tmp; do + test -e "$m" \ + && mnt_m=$( getmntpoint "$m" ) \ + && test "$mnt_root" != "$mnt_m" \ + || continue + + found=1 + echo "$m" > exp || framework_failure_ + + # Option -mount skips. + find / -maxdepth 1 -mount -path "$m" -print > out-m || fail=1 + compare /dev/null out-m || fail=1 + + # Option -xdev does not skip (but would skip sub-directories). + find / -maxdepth 1 -xdev -path "$m" -print > out-x || fail=1 + compare exp out-x || fail=1 + + # Options -mount -xdev shall skip as well (-xdev has no effect). + find / -maxdepth 1 -mount -xdev -path "$m" -print > out-mx || fail=1 + compare /dev/null out-m || fail=1 +done + +test $found -gt 0 \ + || skip_ "cannot determine other device mounts in '/'" + +Exit $fail diff --git a/tests/local.mk b/tests/local.mk index d07745cd..c2198ca0 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -137,6 +137,7 @@ sh_tests = \ tests/xargs/conflicting_opts.sh \ tests/xargs/verbose-quote.sh \ tests/find/arg-nan.sh \ + tests/find/mount-vs-xdev.sh \ $(all_root_tests) $(TEST_LOGS): $(PROGRAMS) -- 2.52.0
0004-find-add-more-mount-tests-check-root.patch
(text/x-patch, 6.5 KB)
From 04738593b485e4013b49af4e8017d603af1cd567 Mon Sep 17 00:00:00 2001 From: Bernhard Voelker <[email protected]> Date: Sun, 28 Dec 2025 17:39:22 +0100 Subject: [PATCH 4/4] find: add more -mount tests (check-root) Add some more tests exercising bind mounts on the same device which should not be affected by -mount or -xdev, and tests with a loopback file system and a bind mount from there. * tests/find/mount-vs-xdev-bind.sh: Add test. * tests/find/mount-vs-xdev-other-fs.sh: Likewise. * tests/local.mk (all_root_tests): Reference them. --- tests/find/mount-vs-xdev-bind.sh | 77 ++++++++++++++++++++++++++++ tests/find/mount-vs-xdev-other-fs.sh | 77 ++++++++++++++++++++++++++++ tests/local.mk | 4 +- 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100755 tests/find/mount-vs-xdev-bind.sh create mode 100755 tests/find/mount-vs-xdev-other-fs.sh diff --git a/tests/find/mount-vs-xdev-bind.sh b/tests/find/mount-vs-xdev-bind.sh new file mode 100755 index 00000000..80104520 --- /dev/null +++ b/tests/find/mount-vs-xdev-bind.sh @@ -0,0 +1,77 @@ +#!/bin/sh +# Exercise find -mount vs. -xdev behaviour for bind mounts (on same device). + +# Copyright (C) 2026 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; fu_path_prepend_ +print_ver_ find + +# The test setup requires root permissions (while the pure test run would not). +require_root_ + +cwd=$(pwd) +cleanup_() { + cd /; + test -s "$cwd/mntf" \ + && umount "$cwd/mntf" + umount "$cwd/mnt" +} + +mkdir d mnt || framework_failure_ +> d/f || framework_failure_ + +# Bind mounts have the same device ID; hence -mount/-xdev shall not skip them. +mount --bind d mnt \ + || skip_ "This test requires mount with a working --bind option." + +mnt_f='./mnt/f' +echo "$mnt_f" > exp || framework_failure_ + +find -path "$mnt_f" > out || fail=1 +compare exp out || fail=1 + +find -xdev -path "$mnt_f" > out-x || fail=1 +compare exp out-x || fail=1 + +find -mount -path "$mnt_f" > out-m || fail=1 +compare exp out-m || fail=1 + +find -mount -xdev -path "$mnt_f" > out-mx || fail=1 +compare exp out-mx || fail=1 + +# Now exercise a bind mount of a regular file. Also this has the same device ID, +# and hence -mount -xdev shall also not affect find(1). +echo test > file || framework_failure_ +> mntf || framework_failure_ + +mount --bind file mntf \ + || skip_ "This test requires mount with a working --bind option." + +echo './mntf' > exp || framework_failure_ + +find -path './mntf' > out || fail=1 +compare exp out || fail=1 + +find -xdev -path './mntf' > out-x || fail=1 +compare exp out-x || fail=1 + +find -mount -path './mntf' > out-m || fail=1 +compare exp out-m || fail=1 + +find -mount -xdev -path './mntf' > out-mx || fail=1 +compare exp out-mx || fail=1 + +Exit $fail diff --git a/tests/find/mount-vs-xdev-other-fs.sh b/tests/find/mount-vs-xdev-other-fs.sh new file mode 100755 index 00000000..93e14aaf --- /dev/null +++ b/tests/find/mount-vs-xdev-other-fs.sh @@ -0,0 +1,77 @@ +#!/bin/sh +# Exercise find -mount vs. -xdev behaviour with another file system. + +# Copyright (C) 2026 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +. "${srcdir=.}/tests/init.sh"; fu_path_prepend_ +print_ver_ find + +# The test setup requires root permissions (while the pure test run would not). +require_root_ + +cwd=$(pwd) +cleanup_() { + cd / + test -s "$cwd/mntf" \ + && umount "$cwd/mntf" + umount "$cwd/mnt" +} + +mkdir d mnt || framework_failure_ + +# Mount an ext2 loopback file system at 'mnt'. +dd if=/dev/zero of='fs' bs=8192 count=200 2>/dev/null || framework_failure_ +mkfs -t ext2 -F 'fs' || skip_ "failed to create ext2 file system" +mount -oloop fs mnt \ + || skip_ 'insufficient mount/ext2 support' + +echo test > mnt/file || framework_failure_ +echo './mnt/file' > exp || framework_failure_ + +find -name 'file' > out || fail=1 +find -xdev -name 'file' > out-x || fail=1 +find -mount -name 'file' > out-m || fail=1 +find -mount -xdev -name 'file' > out-mx || fail=1 + +# Only the run without -mount and/or -xdev found 'mnt/file'. +compare exp out || fail=1 +compare /dev/null out-x || fail=1 +compare /dev/null out-m || fail=1 +compare /dev/null out-mx || fail=1 + +# Now bind-mount 'mnt/file' back on 'mntf' into the current file system. +> mntf || framework_failure_ +mount --bind mnt/file mntf \ + || skip_ "This test requires mount with a working --bind option." + + +# Only the run without options and pure -xdev should find the file 'mntf', +# and the runs with -mount (with or without -xdev) should ignore it. +echo './mntf' > exp || framework_failure_ + +find -name mntf > out || fail=1 +compare exp out || fail=1 + +find -xdev -name mntf > out-x || fail=1 +compare exp out-x || fail=1 + +find -mount -name mntf > out-m || fail=1 +compare /dev/null out-m || fail=1 + +find -mount -xdev -name mntf > out-mx || fail=1 +compare /dev/null out-mx || fail=1 + +Exit $fail diff --git a/tests/local.mk b/tests/local.mk index c2198ca0..bb575c1b 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -85,7 +85,9 @@ EXTRA_DIST += \ tests/sample-test all_root_tests = \ - tests/find/type_list.sh + tests/find/type_list.sh \ + tests/find/mount-vs-xdev-bind.sh \ + tests/find/mount-vs-xdev-other-fs.sh check_PROGRAMS = $(binary_tests) binary_tests = \ -- 2.52.0