[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] find: -exec is terminated by + only if the prior arg is exactly
From: |
James Youngman |
Subject: |
[PATCH] find: -exec is terminated by + only if the prior arg is exactly '{}' |
Date: |
Sat, 2 Nov 2024 18:44:08 +0000 |
A "+" only terminates -exec when it immediately follows an argument
which is exactly "{}" (and not, for example, "{}x"). This fixes
Savannah bug 66365.
* NEWS: explain this change.
* doc/find.texi: update one place which omitted the '{}' before '+'.
* find/parser.c (insert_exec_ok): consider + to be special ony if it
follows an argument which is exactly '{}'.
* tests/find/sv-bug-66365-exec.sh: test for this bug.
* tests/local.mk: add the new test file.
---
NEWS | 6 ++++++
doc/find.texi | 2 +-
find/parser.c | 23 +++++++++++++++--------
tests/find/sv-bug-66365-exec.sh | 27 +++++++++++++++++++++++++++
tests/local.mk | 1 +
5 files changed, 50 insertions(+), 9 deletions(-)
create mode 100644 tests/find/sv-bug-66365-exec.sh
diff --git a/NEWS b/NEWS
index ae8c4a26..3276887a 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,12 @@ GNU findutils NEWS - User visible changes. -*- outline
-*- (allout)
'find -ignore_readdir_race' now has a race between FTS read and the visiting
of the entry when the file was removed. [#45930]
+ To fix a POSIX compatibility bug, -exec foo Z{} + is no longer a
+ complete predicate, because '+' is only a terminator when it follows
+ an argument which is exactly '{}'. The findutils documentation
+ already states this, and now find's behaviour matches the
+ documentation.
+
** Documentation Changes
The forthcoming Issue 8 of the POSIX standard will standardise "find
diff --git a/doc/find.texi b/doc/find.texi
index 4cae7419..9f63c8fb 100644
--- a/doc/find.texi
+++ b/doc/find.texi
@@ -1536,7 +1536,7 @@ This is different to @samp{-prune} because @samp{-prune}
only applies
to the contents of pruned directories, while @samp{-quit} simply makes
@code{find} stop immediately. No child processes will be left
running. Any command lines which have been built by @samp{-exec
-... \+} or @samp{-execdir ... \+} are invoked before the program is
+... @{@} +} or @samp{-execdir ... \+} are invoked before the program is
exited. After @samp{-quit} is executed, no more files specified on
the command line will be processed. For example, @samp{find /tmp/foo
/tmp/bar -print -quit} will print only @samp{/tmp/foo}. One common
diff --git a/find/parser.c b/find/parser.c
index ad3b9904..1b389b3c 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -2770,7 +2770,7 @@ insert_exec_ok (const char *action,
{
int start, end; /* Indexes in ARGV of start & end of cmd. */
int i; /* Index into cmd args */
- int saw_braces; /* True if previous arg was '{}'. */
+ bool prev_was_braces_only; /* Previous arg was '{}' (not e.g. 'Q' or
'{}x'). */
bool allow_plus; /* True if + is a valid terminator */
int brace_count; /* Number of instances of {}. */
const char *brace_arg; /* Which arg did {} appear in? */
@@ -2827,28 +2827,35 @@ insert_exec_ok (const char *action,
* Also figure out if the command is terminated by ";" or by "+".
*/
start = *arg_ptr;
- for (end = start, saw_braces=0, brace_count=0, brace_arg=NULL;
+ for (end = start, prev_was_braces_only=false, brace_count=0, brace_arg=NULL;
(argv[end] != NULL)
&& ((argv[end][0] != ';') || (argv[end][1] != '\0'));
end++)
{
/* For -exec and -execdir, "{} +" can terminate the command. */
- if ( allow_plus
- && argv[end][0] == '+' && argv[end][1] == 0
- && saw_braces)
+ if (allow_plus && prev_was_braces_only
+ && argv[end][0] == '+' && argv[end][1] == 0)
{
our_pred->args.exec_vec.multiple = 1;
break;
}
- saw_braces = 0;
+ prev_was_braces_only = false;
if (mbsstr (argv[end], "{}"))
{
- saw_braces = 1;
+ if (0 == strcmp(argv[end], "{}"))
+ {
+ /* Savannah bug 66365: + only terminates the predicate
+ * immediately after an argument which is exactly, "{}".
+ * However, the "{}" in "x{}" should get expanded for
+ * the ";" case.
+ */
+ prev_was_braces_only = true;
+ }
brace_arg = argv[end];
++brace_count;
- if (0 == end && (func == pred_execdir || func == pred_okdir))
+ if (start == end && (func == pred_execdir || func == pred_okdir))
{
/* The POSIX standard says that {} replacement should
* occur even in the utility name. This is insecure
diff --git a/tests/find/sv-bug-66365-exec.sh b/tests/find/sv-bug-66365-exec.sh
new file mode 100644
index 00000000..79ac3f3d
--- /dev/null
+++ b/tests/find/sv-bug-66365-exec.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Test that find -exec ... + treats the + as a terminator only when it
+# immediately follows a {}. See Savannah bug #66365.
+
+# Copyright (C) 2024 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
+
+find . -prune -exec echo x{} + \; >| out
+echo 'x. +' >| exp || framework_failure_
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/local.mk b/tests/local.mk
index 7a602c5e..34798451 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -130,6 +130,7 @@ sh_tests = \
tests/find/used.sh \
tests/find/newer.sh \
tests/find/opt-numeric-arg.sh \
+ tests/find/sv-bug-66365-exec.sh \
tests/find/user-group-max.sh \
tests/xargs/conflicting_opts.sh \
tests/xargs/verbose-quote.sh \
--
2.39.5
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [PATCH] find: -exec is terminated by + only if the prior arg is exactly '{}',
James Youngman <=