|
|
7b76bb |
From 443166adaf1c8b91e16a716f3b13f47493b895cc Mon Sep 17 00:00:00 2001
|
|
|
7b76bb |
From: Bernhard Voelker <mail@bernhard-voelker.de>
|
|
|
7b76bb |
Date: Tue, 31 May 2016 10:38:52 +0200
|
|
|
7b76bb |
Subject: [PATCH] Fix bug #48030: find: -exec + does not pass all arguments in
|
|
|
7b76bb |
certain cases
|
|
|
7b76bb |
|
|
|
7b76bb |
When the -exec arguments buffer (usually 128k) is full and the given
|
|
|
7b76bb |
command has been executed with all that arguments, find(1) missed to
|
|
|
7b76bb |
execute the command yet another time if only 1 another file would have
|
|
|
7b76bb |
to be processed.
|
|
|
7b76bb |
Both find(1), i.e., nowadays FTS-version, and oldfind are affected.
|
|
|
7b76bb |
This bug was present since the implementation of '-exec +' in 2005,
|
|
|
7b76bb |
see commit FINDUTILS_4_2_11-1-25-gf0a6ac6.
|
|
|
7b76bb |
|
|
|
7b76bb |
* lib/buildcmd.c (bc_push_arg): Move the assignment to set 'state->todo'
|
|
|
7b76bb |
to 1 down after the immediate execution which resets that flag.
|
|
|
7b76bb |
* find/testsuite/sv-48030-exec-plus-bug.sh: Add a test.
|
|
|
7b76bb |
* find/testsuite/Makefile.am (test_shell_progs): Reference the test.
|
|
|
7b76bb |
* NEWS (Bug Fixes): Mention the fix.
|
|
|
7b76bb |
|
|
|
7b76bb |
Reported by Joe Philip Ninan <indiajoe@gmail.com> in
|
|
|
7b76bb |
https://savannah.gnu.org/bugs/?48030
|
|
|
7b76bb |
|
|
|
7b76bb |
Upstream-commit: 8cdc9767e305c9566f537af9d1acf71d1bc6ee8e
|
|
|
7b76bb |
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
|
7b76bb |
---
|
|
|
7b76bb |
find/testsuite/Makefile.am | 3 +-
|
|
|
7b76bb |
find/testsuite/sv-48030-exec-plus-bug.sh | 143 +++++++++++++++++++++++++++++++
|
|
|
7b76bb |
lib/buildcmd.c | 10 +--
|
|
|
7b76bb |
3 files changed, 150 insertions(+), 6 deletions(-)
|
|
|
7b76bb |
create mode 100644 find/testsuite/sv-48030-exec-plus-bug.sh
|
|
|
7b76bb |
|
|
|
7b76bb |
diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am
|
|
|
7b76bb |
index c1369c3..ab5dbe8 100644
|
|
|
7b76bb |
--- a/find/testsuite/Makefile.am
|
|
|
7b76bb |
+++ b/find/testsuite/Makefile.am
|
|
|
7b76bb |
@@ -258,7 +258,8 @@ test_escapechars.sh \
|
|
|
7b76bb |
test_escape_c.sh \
|
|
|
7b76bb |
test_inode.sh \
|
|
|
7b76bb |
sv-34079.sh \
|
|
|
7b76bb |
-sv-34976-execdir-fd-leak.sh
|
|
|
7b76bb |
+sv-34976-execdir-fd-leak.sh \
|
|
|
7b76bb |
+sv-48030-exec-plus-bug.sh
|
|
|
7b76bb |
|
|
|
7b76bb |
EXTRA_DIST = $(EXTRA_DIST_EXP) $(EXTRA_DIST_XO) $(EXTRA_DIST_GOLDEN) \
|
|
|
7b76bb |
$(test_shell_progs) binary_locations.sh checklists.py
|
|
|
7b76bb |
diff --git a/find/testsuite/sv-48030-exec-plus-bug.sh b/find/testsuite/sv-48030-exec-plus-bug.sh
|
|
|
7b76bb |
new file mode 100755
|
|
|
7b76bb |
index 0000000..4dbf149
|
|
|
7b76bb |
--- /dev/null
|
|
|
7b76bb |
+++ b/find/testsuite/sv-48030-exec-plus-bug.sh
|
|
|
7b76bb |
@@ -0,0 +1,143 @@
|
|
|
7b76bb |
+#! /bin/sh
|
|
|
7b76bb |
+# Copyright (C) 2016 Free Software Foundation, Inc.
|
|
|
7b76bb |
+#
|
|
|
7b76bb |
+# This program is free software: you can redistribute it and/or modify
|
|
|
7b76bb |
+# it under the terms of the GNU General Public License as published by
|
|
|
7b76bb |
+# the Free Software Foundation, either version 3 of the License, or
|
|
|
7b76bb |
+# (at your option) any later version.
|
|
|
7b76bb |
+#
|
|
|
7b76bb |
+# This program is distributed in the hope that it will be useful,
|
|
|
7b76bb |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
7b76bb |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
7b76bb |
+# GNU General Public License for more details.
|
|
|
7b76bb |
+#
|
|
|
7b76bb |
+# You should have received a copy of the GNU General Public License
|
|
|
7b76bb |
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
7b76bb |
+#
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+# This test verifies that find invokes the given command for the
|
|
|
7b76bb |
+# multiple-argument sytax '-exec CMD {} +'. Between FINDUTILS-4.2.12
|
|
|
7b76bb |
+# and v4.6.0, find(1) would have failed to execute CMD another time
|
|
|
7b76bb |
+# if there was only one last single file argument.
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+testname="$(basename $0)"
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+. "${srcdir}"/binary_locations.sh
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+die() {
|
|
|
7b76bb |
+ echo "$@" >&2
|
|
|
7b76bb |
+ exit 1
|
|
|
7b76bb |
+}
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+# This is used to simplify checking of the return value
|
|
|
7b76bb |
+# which is useful when ensuring a command fails as desired.
|
|
|
7b76bb |
+# I.e., just doing `command ... &&fail=1` will not catch
|
|
|
7b76bb |
+# a segfault in command for example. With this helper you
|
|
|
7b76bb |
+# instead check an explicit exit code like
|
|
|
7b76bb |
+# returns_ 1 command ... || fail
|
|
|
7b76bb |
+returns_ () {
|
|
|
7b76bb |
+ # Disable tracing so it doesn't interfere with stderr of the wrapped command
|
|
|
7b76bb |
+ { set +x; } 2>/dev/null
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+ local exp_exit="$1"
|
|
|
7b76bb |
+ shift
|
|
|
7b76bb |
+ "$@"
|
|
|
7b76bb |
+ test $? -eq $exp_exit && ret_=0 || ret_=1
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+ set -x
|
|
|
7b76bb |
+ { return $ret_; } 2>/dev/null
|
|
|
7b76bb |
+}
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+# Define the nicest compare available (borrowed from gnulib).
|
|
|
7b76bb |
+if diff_out_=`exec 2>/dev/null; diff -u "$0" "$0" < /dev/null` \
|
|
|
7b76bb |
+ && diff -u Makefile "$0" 2>/dev/null | grep '^[+]#!' >/dev/null; then
|
|
|
7b76bb |
+ # diff accepts the -u option and does not (like AIX 7 'diff') produce an
|
|
|
7b76bb |
+ # extra space on column 1 of every content line.
|
|
|
7b76bb |
+ if test -z "$diff_out_"; then
|
|
|
7b76bb |
+ compare () { diff -u "$@"; }
|
|
|
7b76bb |
+ else
|
|
|
7b76bb |
+ compare ()
|
|
|
7b76bb |
+ {
|
|
|
7b76bb |
+ if diff -u "$@" > diff.out; then
|
|
|
7b76bb |
+ # No differences were found, but Solaris 'diff' produces output
|
|
|
7b76bb |
+ # "No differences encountered". Hide this output.
|
|
|
7b76bb |
+ rm -f diff.out
|
|
|
7b76bb |
+ true
|
|
|
7b76bb |
+ else
|
|
|
7b76bb |
+ cat diff.out
|
|
|
7b76bb |
+ rm -f diff.out
|
|
|
7b76bb |
+ false
|
|
|
7b76bb |
+ fi
|
|
|
7b76bb |
+ }
|
|
|
7b76bb |
+ fi
|
|
|
7b76bb |
+elif diff_out_=`exec 2>/dev/null; diff -c "$0" "$0" < /dev/null`; then
|
|
|
7b76bb |
+ if test -z "$diff_out_"; then
|
|
|
7b76bb |
+ compare () { diff -c "$@"; }
|
|
|
7b76bb |
+ else
|
|
|
7b76bb |
+ compare ()
|
|
|
7b76bb |
+ {
|
|
|
7b76bb |
+ if diff -c "$@" > diff.out; then
|
|
|
7b76bb |
+ # No differences were found, but AIX and HP-UX 'diff' produce output
|
|
|
7b76bb |
+ # "No differences encountered" or "There are no differences between the
|
|
|
7b76bb |
+ # files.". Hide this output.
|
|
|
7b76bb |
+ rm -f diff.out
|
|
|
7b76bb |
+ true
|
|
|
7b76bb |
+ else
|
|
|
7b76bb |
+ cat diff.out
|
|
|
7b76bb |
+ rm -f diff.out
|
|
|
7b76bb |
+ false
|
|
|
7b76bb |
+ fi
|
|
|
7b76bb |
+ }
|
|
|
7b76bb |
+ fi
|
|
|
7b76bb |
+elif cmp -s /dev/null /dev/null 2>/dev/null; then
|
|
|
7b76bb |
+ compare () { cmp -s "$@"; }
|
|
|
7b76bb |
+else
|
|
|
7b76bb |
+ compare () { cmp "$@"; }
|
|
|
7b76bb |
+fi
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+DIR='RashuBug'
|
|
|
7b76bb |
+# Name of the CMD to execute: the file name must be 6 characters long
|
|
|
7b76bb |
+# (to trigger the bug in combination with the test files).
|
|
|
7b76bb |
+CMD='tstcmd'
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+# Create test files.
|
|
|
7b76bb |
+make_test_data() {
|
|
|
7b76bb |
+ # Create the CMD script and check that it works.
|
|
|
7b76bb |
+ mkdir "$DIR" 'bin' \
|
|
|
7b76bb |
+ && echo 'printf "%s\n" "$@"' > "bin/$CMD" \
|
|
|
7b76bb |
+ && chmod +x "bin/$CMD" \
|
|
|
7b76bb |
+ && PATH="$PWD/bin:$PATH" \
|
|
|
7b76bb |
+ && [ $( "${ftsfind}" bin -maxdepth 0 -exec "$CMD" '{}' + ) = 'bin' ] \
|
|
|
7b76bb |
+ || return 1
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+ # Create expected output file - also used for creating the test data.
|
|
|
7b76bb |
+ { seq -f "${DIR}/abcdefghijklmnopqrstuv%04g" 901 &&
|
|
|
7b76bb |
+ seq -f "${DIR}/abcdefghijklmnopqrstu%04g" 902 3719
|
|
|
7b76bb |
+ } > exp2 \
|
|
|
7b76bb |
+ && LC_ALL=C sort exp2 > exp \
|
|
|
7b76bb |
+ && rm exp2 \
|
|
|
7b76bb |
+ || return 1
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+ # Create test files, and check if test data has been created correctly.
|
|
|
7b76bb |
+ xargs touch < exp \
|
|
|
7b76bb |
+ && [ -f "${DIR}/abcdefghijklmnopqrstu3719" ] \
|
|
|
7b76bb |
+ && [ 3719 = $( "${ftsfind}" "$DIR" -type f | wc -l ) ] \
|
|
|
7b76bb |
+ || return 1
|
|
|
7b76bb |
+}
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+set -x
|
|
|
7b76bb |
+tmpdir="$(mktemp -d)" \
|
|
|
7b76bb |
+ && cd "$tmpdir" \
|
|
|
7b76bb |
+ && make_test_data "${tmpdir}" \
|
|
|
7b76bb |
+ || die "FAIL: failed to set up the test in ${tmpdir}"
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+fail=0
|
|
|
7b76bb |
+for exe in "${ftsfind}" "${oldfind}"; do
|
|
|
7b76bb |
+ "$exe" "$DIR" -type f -exec "$CMD" '{}' + > out || fail=1
|
|
|
7b76bb |
+ LC_ALL=C sort out > out2 || fail=1
|
|
|
7b76bb |
+ compare exp out2 || fail=1
|
|
|
7b76bb |
+done
|
|
|
7b76bb |
+
|
|
|
7b76bb |
+cd ..
|
|
|
7b76bb |
+rm -rf "${tmpdir}" || exit 1
|
|
|
7b76bb |
+exit $fail
|
|
|
7b76bb |
diff --git a/lib/buildcmd.c b/lib/buildcmd.c
|
|
|
7b76bb |
index a58f67e..27e9ce5 100644
|
|
|
7b76bb |
--- a/lib/buildcmd.c
|
|
|
7b76bb |
+++ b/lib/buildcmd.c
|
|
|
7b76bb |
@@ -356,11 +356,6 @@ bc_push_arg (struct buildcmd_control *ctl,
|
|
|
7b76bb |
|
|
|
7b76bb |
assert (arg != NULL);
|
|
|
7b76bb |
|
|
|
7b76bb |
- if (!initial_args)
|
|
|
7b76bb |
- {
|
|
|
7b76bb |
- state->todo = 1;
|
|
|
7b76bb |
- }
|
|
|
7b76bb |
-
|
|
|
7b76bb |
if (!terminate)
|
|
|
7b76bb |
{
|
|
|
7b76bb |
if (state->cmd_argv_chars + len + pfxlen > ctl->arg_max)
|
|
|
7b76bb |
@@ -380,6 +375,11 @@ bc_push_arg (struct buildcmd_control *ctl,
|
|
|
7b76bb |
bc_do_exec (ctl, state);
|
|
|
7b76bb |
}
|
|
|
7b76bb |
|
|
|
7b76bb |
+ if (!initial_args)
|
|
|
7b76bb |
+ {
|
|
|
7b76bb |
+ state->todo = 1;
|
|
|
7b76bb |
+ }
|
|
|
7b76bb |
+
|
|
|
7b76bb |
if (state->cmd_argc >= state->cmd_argv_alloc)
|
|
|
7b76bb |
{
|
|
|
7b76bb |
/* XXX: we could use extendbuf() here. */
|
|
|
7b76bb |
--
|
|
|
7b76bb |
2.5.5
|
|
|
7b76bb |
|