Blame SOURCES/findutils-4.6.0-exec-args.patch

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