bin/79263: find -exec {} + fails with -or and !
Jilles Tjoelker
jilles at stack.nl
Sat Mar 26 11:40:03 PST 2005
>Number: 79263
>Category: bin
>Synopsis: find -exec {} + fails with -or and !
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Sat Mar 26 19:40:03 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator: Jilles Tjoelker
>Release: FreeBSD 5.3-RELEASE-p5 i386
>Organization:
MCGV Stack
>Environment:
System: FreeBSD turtle.stack.nl 5.3-RELEASE-p5 FreeBSD 5.3-RELEASE-p5 #7: Thu Mar 10 11:12:03 CET 2005 marcolz at snail.stack.nl:/usr/obj/usr/src/sys/SNAIL i386
find(1) in HEAD is almost the same.
>Description:
The last (possibly only) execution of -exec {} + is not done if the -exec
primary is not on the top-level -and sequence, e.g. inside a ! or -or.
>How-To-Repeat:
Simple not-so-practical example (/home/jilles/tmp/find is the patched version
of /usr/src/usr.bin/find):
jilles at jaguar /home/jilles/tmp% find find \! -exec echo {} +
(no output)
jilles at jaguar /home/jilles/tmp% find/find find \! -exec echo {} +
find find/option.c find/extern.h find/find.1 find/find.c find/find.h find/function.c find/getdate.y find/ls.c find/main.c find/misc.c find/operator.c find/Makefile find/find.o find/function.o find/ls.o find/main.o find/misc.o find/operator.o find/option.o find/getdate.c find/getdate.o find/find find/find.1.gz
(expected output)
Practical example (searching through a Subversion checkout):
jilles at jaguar /home/jilles/src/svn/hyperion% find . \( -name .svn -prune \) -o -type f -exec grep -i silence /dev/null {} +
(no output)
jilles at jaguar /home/jilles/src/svn/hyperion% ~/tmp/find/find . \( -name .svn -prune \) -o -type f -exec grep -i silence /dev/null {} +
(expected output, snipped here)
In comparison:
jilles at jaguar /home/jilles/src/svn/hyperion% find . \( -name .svn -prune \) -o -type f -print0 | xargs -0 grep -i silence /dev/null
gives the expected output, even without the patch.
>Fix:
Patch included.
Create a separate linked list of all active -exec {} + primaries and do the
last execution for all at termination.
--- find.patch begins here ---
diff -ur /usr/src/usr.bin/find/extern.h find/extern.h
--- /usr/src/usr.bin/find/extern.h Thu Jul 29 05:29:44 2004
+++ find/extern.h Sat Mar 26 20:11:04 2005
@@ -49,6 +49,7 @@
void printlong(char *, char *, struct stat *);
int queryuser(char **);
OPTION *lookup_option(const char *);
+void finish_execplus(void);
creat_f c_Xmin;
creat_f c_Xtime;
diff -ur /usr/src/usr.bin/find/find.c find/find.c
--- /usr/src/usr.bin/find/find.c Fri May 28 19:17:15 2004
+++ find/find.c Sat Mar 26 20:09:23 2005
@@ -231,10 +231,7 @@
*/
for (p = plan; p && (p->execute)(p, entry); p = p->next);
}
- /* Finish any pending -exec ... {} + functions. */
- for (p = plan; p != NULL; p = p->next)
- if (p->execute == f_exec && p->flags & F_EXECPLUS)
- (p->execute)(p, NULL);
+ finish_execplus();
if (errno)
err(1, "fts_read");
return (rval);
diff -ur /usr/src/usr.bin/find/find.h find/find.h
--- /usr/src/usr.bin/find/find.h Fri May 28 19:17:15 2004
+++ find/find.h Sat Mar 26 19:55:31 2005
@@ -103,6 +103,7 @@
int _e_psize; /* number of bytes of args. */
int _e_pbsize; /* base num. of bytes of args */
int _e_psizemax; /* max num. of bytes of args */
+ struct _plandata *_e_next;/* next F_EXECPLUS in tree */
} ex;
char *_a_data[2]; /* array of char pointers */
char *_c_data; /* char pointer */
@@ -133,6 +134,7 @@
#define e_psize p_un.ex._e_psize
#define e_pbsize p_un.ex._e_pbsize
#define e_psizemax p_un.ex._e_psizemax
+#define e_next p_un.ex._e_next
typedef struct _option {
const char *name; /* option name */
Only in find: find.o
diff -ur /usr/src/usr.bin/find/function.c find/function.c
--- /usr/src/usr.bin/find/function.c Thu Jul 29 05:33:55 2004
+++ find/function.c Sat Mar 26 20:11:06 2005
@@ -76,6 +76,8 @@
extern char **environ;
+static PLAN *lastexecplus = NULL;
+
#define COMPARE(a, b) do { \
switch (plan->flags & F_ELG_MASK) { \
case F_EQUAL: \
@@ -704,6 +706,8 @@
new->e_psizemax = argmax;
new->e_pbsize = 0;
cnt += new->e_pnummax + 1;
+ new->e_next = lastexecplus;
+ lastexecplus = new;
}
if ((new->e_argv = malloc(cnt * sizeof(char *))) == NULL)
err(1, NULL);
@@ -745,6 +749,19 @@
done: *argvp = argv + 1;
return new;
+}
+
+/* Finish any pending -exec ... {} + functions. */
+void
+finish_execplus()
+{
+ PLAN *p;
+
+ p = lastexecplus;
+ while (p != NULL) {
+ (p->execute)(p, NULL);
+ p = p->e_next;
+ }
}
int
--- find.patch ends here ---
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list