Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 26 Mar 2005 20:38:50 +0100 (CET)
From:      Jilles Tjoelker <jilles@stack.nl>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   bin/79263: find -exec {} + fails with -or and !
Message-ID:  <20050326193850.98BBF1CD4B@turtle.stack.nl>
Resent-Message-ID: <200503261940.j2QJe3Wa019400@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>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@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@jaguar /home/jilles/tmp% find find \! -exec echo {} +

(no output)

jilles@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@jaguar /home/jilles/src/svn/hyperion% find . \( -name .svn -prune \) -o -type f -exec grep -i silence /dev/null {} +

(no output)

jilles@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@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:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050326193850.98BBF1CD4B>