xref: /freebsd/usr.bin/find/function.c (revision 8a0a76b862df8763ff2b90c633ccb90e4ece6032)
19b50d902SRodney W. Grimes /*-
29b50d902SRodney W. Grimes  * Copyright (c) 1990, 1993
39b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
49b50d902SRodney W. Grimes  *
59b50d902SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
69b50d902SRodney W. Grimes  * Cimarron D. Taylor of the University of California, Berkeley.
79b50d902SRodney W. Grimes  *
89b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
99b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
109b50d902SRodney W. Grimes  * are met:
119b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
129b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
139b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
149b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
159b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
169b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
179b50d902SRodney W. Grimes  *    must display the following acknowledgement:
189b50d902SRodney W. Grimes  *	This product includes software developed by the University of
199b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
209b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
219b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
229b50d902SRodney W. Grimes  *    without specific prior written permission.
239b50d902SRodney W. Grimes  *
249b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
259b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
269b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
279b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
289b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
299b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
309b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
319b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
329b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
339b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
349b50d902SRodney W. Grimes  * SUCH DAMAGE.
359b50d902SRodney W. Grimes  */
369b50d902SRodney W. Grimes 
379b50d902SRodney W. Grimes #ifndef lint
38c76bc8f3SOllivier Robert #if 0
39c76bc8f3SOllivier Robert static const char sccsid[] = "@(#)function.c	8.10 (Berkeley) 5/4/95";
40c76bc8f3SOllivier Robert #endif
419b50d902SRodney W. Grimes #endif /* not lint */
42ef646f18SMark Murray 
433077469eSDavid E. O'Brien #include <sys/cdefs.h>
443077469eSDavid E. O'Brien __FBSDID("$FreeBSD$");
459b50d902SRodney W. Grimes 
469b50d902SRodney W. Grimes #include <sys/param.h>
479b50d902SRodney W. Grimes #include <sys/ucred.h>
489b50d902SRodney W. Grimes #include <sys/stat.h>
499c5d31dfSBosko Milekic #include <sys/types.h>
509c5d31dfSBosko Milekic #include <sys/acl.h>
519b50d902SRodney W. Grimes #include <sys/wait.h>
529b50d902SRodney W. Grimes #include <sys/mount.h>
53ea92232aSPoul-Henning Kamp #include <sys/timeb.h>
549b50d902SRodney W. Grimes 
55ed1a4621SPeter Wemm #include <dirent.h>
569b50d902SRodney W. Grimes #include <err.h>
579b50d902SRodney W. Grimes #include <errno.h>
589b50d902SRodney W. Grimes #include <fnmatch.h>
599b50d902SRodney W. Grimes #include <fts.h>
609b50d902SRodney W. Grimes #include <grp.h>
615e25d888STim J. Robbins #include <limits.h>
629b50d902SRodney W. Grimes #include <pwd.h>
637c1d4b3aSAkinori MUSHA #include <regex.h>
649b50d902SRodney W. Grimes #include <stdio.h>
659b50d902SRodney W. Grimes #include <stdlib.h>
669b50d902SRodney W. Grimes #include <string.h>
679b50d902SRodney W. Grimes #include <unistd.h>
681c832963SOliver Eikemeier #include <ctype.h>
699b50d902SRodney W. Grimes 
709b50d902SRodney W. Grimes #include "find.h"
719b50d902SRodney W. Grimes 
72ecca1f1cSMark Murray static PLAN *palloc(OPTION *);
73ecca1f1cSMark Murray static long long find_parsenum(PLAN *, const char *, char *, char *);
74ecca1f1cSMark Murray static long long find_parsetime(PLAN *, const char *, char *);
75ecca1f1cSMark Murray static char *nextarg(OPTION *, char ***);
76ea92232aSPoul-Henning Kamp 
77a07af811STim J. Robbins extern char **environ;
78a07af811STim J. Robbins 
79adff4fcaSRuslan Ermilov #define	COMPARE(a, b) do {						\
80ea92232aSPoul-Henning Kamp 	switch (plan->flags & F_ELG_MASK) {				\
819b50d902SRodney W. Grimes 	case F_EQUAL:							\
829b50d902SRodney W. Grimes 		return (a == b);					\
839b50d902SRodney W. Grimes 	case F_LESSTHAN:						\
849b50d902SRodney W. Grimes 		return (a < b);						\
859b50d902SRodney W. Grimes 	case F_GREATER:							\
869b50d902SRodney W. Grimes 		return (a > b);						\
879b50d902SRodney W. Grimes 	default:							\
889b50d902SRodney W. Grimes 		abort();						\
899b50d902SRodney W. Grimes 	}								\
90adff4fcaSRuslan Ermilov } while(0)
919b50d902SRodney W. Grimes 
92ea92232aSPoul-Henning Kamp static PLAN *
93ef646f18SMark Murray palloc(OPTION *option)
94ea92232aSPoul-Henning Kamp {
95ea92232aSPoul-Henning Kamp 	PLAN *new;
96ea92232aSPoul-Henning Kamp 
97ea92232aSPoul-Henning Kamp 	if ((new = malloc(sizeof(PLAN))) == NULL)
98ea92232aSPoul-Henning Kamp 		err(1, NULL);
99ea92232aSPoul-Henning Kamp 	new->execute = option->execute;
100ea92232aSPoul-Henning Kamp 	new->flags = option->flags;
101ea92232aSPoul-Henning Kamp 	new->next = NULL;
102ea92232aSPoul-Henning Kamp 	return new;
103ea92232aSPoul-Henning Kamp }
1049b50d902SRodney W. Grimes 
1059b50d902SRodney W. Grimes /*
1069b50d902SRodney W. Grimes  * find_parsenum --
1079b50d902SRodney W. Grimes  *	Parse a string of the form [+-]# and return the value.
1089b50d902SRodney W. Grimes  */
1099192bbf4SBruce Evans static long long
110ef646f18SMark Murray find_parsenum(PLAN *plan, const char *option, char *vp, char *endch)
1119b50d902SRodney W. Grimes {
1129192bbf4SBruce Evans 	long long value;
1139b50d902SRodney W. Grimes 	char *endchar, *str;	/* Pointer to character ending conversion. */
1149b50d902SRodney W. Grimes 
1159b50d902SRodney W. Grimes 	/* Determine comparison from leading + or -. */
1169b50d902SRodney W. Grimes 	str = vp;
1179b50d902SRodney W. Grimes 	switch (*str) {
1189b50d902SRodney W. Grimes 	case '+':
1199b50d902SRodney W. Grimes 		++str;
120ea92232aSPoul-Henning Kamp 		plan->flags |= F_GREATER;
1219b50d902SRodney W. Grimes 		break;
1229b50d902SRodney W. Grimes 	case '-':
1239b50d902SRodney W. Grimes 		++str;
124ea92232aSPoul-Henning Kamp 		plan->flags |= F_LESSTHAN;
1259b50d902SRodney W. Grimes 		break;
1269b50d902SRodney W. Grimes 	default:
127ea92232aSPoul-Henning Kamp 		plan->flags |= F_EQUAL;
1289b50d902SRodney W. Grimes 		break;
1299b50d902SRodney W. Grimes 	}
1309b50d902SRodney W. Grimes 
1319b50d902SRodney W. Grimes 	/*
1329192bbf4SBruce Evans 	 * Convert the string with strtoq().  Note, if strtoq() returns zero
1339b50d902SRodney W. Grimes 	 * and endchar points to the beginning of the string we know we have
1349b50d902SRodney W. Grimes 	 * a syntax error.
1359b50d902SRodney W. Grimes 	 */
1369192bbf4SBruce Evans 	value = strtoq(str, &endchar, 10);
1379b50d902SRodney W. Grimes 	if (value == 0 && endchar == str)
1389b50d902SRodney W. Grimes 		errx(1, "%s: %s: illegal numeric value", option, vp);
1399b50d902SRodney W. Grimes 	if (endchar[0] && (endch == NULL || endchar[0] != *endch))
1409b50d902SRodney W. Grimes 		errx(1, "%s: %s: illegal trailing character", option, vp);
1419b50d902SRodney W. Grimes 	if (endch)
1429b50d902SRodney W. Grimes 		*endch = endchar[0];
143ea92232aSPoul-Henning Kamp 	return value;
1449b50d902SRodney W. Grimes }
1459b50d902SRodney W. Grimes 
1469b50d902SRodney W. Grimes /*
147adff4fcaSRuslan Ermilov  * find_parsetime --
148adff4fcaSRuslan Ermilov  *	Parse a string of the form [+-]([0-9]+[smhdw]?)+ and return the value.
149adff4fcaSRuslan Ermilov  */
150adff4fcaSRuslan Ermilov static long long
151ef646f18SMark Murray find_parsetime(PLAN *plan, const char *option, char *vp)
152adff4fcaSRuslan Ermilov {
153adff4fcaSRuslan Ermilov 	long long secs, value;
154adff4fcaSRuslan Ermilov 	char *str, *unit;	/* Pointer to character ending conversion. */
155adff4fcaSRuslan Ermilov 
156adff4fcaSRuslan Ermilov 	/* Determine comparison from leading + or -. */
157adff4fcaSRuslan Ermilov 	str = vp;
158adff4fcaSRuslan Ermilov 	switch (*str) {
159adff4fcaSRuslan Ermilov 	case '+':
160adff4fcaSRuslan Ermilov 		++str;
161adff4fcaSRuslan Ermilov 		plan->flags |= F_GREATER;
162adff4fcaSRuslan Ermilov 		break;
163adff4fcaSRuslan Ermilov 	case '-':
164adff4fcaSRuslan Ermilov 		++str;
165adff4fcaSRuslan Ermilov 		plan->flags |= F_LESSTHAN;
166adff4fcaSRuslan Ermilov 		break;
167adff4fcaSRuslan Ermilov 	default:
168adff4fcaSRuslan Ermilov 		plan->flags |= F_EQUAL;
169adff4fcaSRuslan Ermilov 		break;
170adff4fcaSRuslan Ermilov 	}
171adff4fcaSRuslan Ermilov 
172adff4fcaSRuslan Ermilov 	value = strtoq(str, &unit, 10);
173adff4fcaSRuslan Ermilov 	if (value == 0 && unit == str) {
174adff4fcaSRuslan Ermilov 		errx(1, "%s: %s: illegal time value", option, vp);
175adff4fcaSRuslan Ermilov 		/* NOTREACHED */
176adff4fcaSRuslan Ermilov 	}
177adff4fcaSRuslan Ermilov 	if (*unit == '\0')
178adff4fcaSRuslan Ermilov 		return value;
179adff4fcaSRuslan Ermilov 
180adff4fcaSRuslan Ermilov 	/* Units syntax. */
181adff4fcaSRuslan Ermilov 	secs = 0;
182adff4fcaSRuslan Ermilov 	for (;;) {
183adff4fcaSRuslan Ermilov 		switch(*unit) {
184adff4fcaSRuslan Ermilov 		case 's':	/* seconds */
185adff4fcaSRuslan Ermilov 			secs += value;
186adff4fcaSRuslan Ermilov 			break;
187adff4fcaSRuslan Ermilov 		case 'm':	/* minutes */
188adff4fcaSRuslan Ermilov 			secs += value * 60;
189adff4fcaSRuslan Ermilov 			break;
190adff4fcaSRuslan Ermilov 		case 'h':	/* hours */
191adff4fcaSRuslan Ermilov 			secs += value * 3600;
192adff4fcaSRuslan Ermilov 			break;
193adff4fcaSRuslan Ermilov 		case 'd':	/* days */
194adff4fcaSRuslan Ermilov 			secs += value * 86400;
195adff4fcaSRuslan Ermilov 			break;
196adff4fcaSRuslan Ermilov 		case 'w':	/* weeks */
197adff4fcaSRuslan Ermilov 			secs += value * 604800;
198adff4fcaSRuslan Ermilov 			break;
199adff4fcaSRuslan Ermilov 		default:
200adff4fcaSRuslan Ermilov 			errx(1, "%s: %s: bad unit '%c'", option, vp, *unit);
201adff4fcaSRuslan Ermilov 			/* NOTREACHED */
202adff4fcaSRuslan Ermilov 		}
203adff4fcaSRuslan Ermilov 		str = unit + 1;
204adff4fcaSRuslan Ermilov 		if (*str == '\0')	/* EOS */
205adff4fcaSRuslan Ermilov 			break;
206adff4fcaSRuslan Ermilov 		value = strtoq(str, &unit, 10);
207adff4fcaSRuslan Ermilov 		if (value == 0 && unit == str) {
208adff4fcaSRuslan Ermilov 			errx(1, "%s: %s: illegal time value", option, vp);
209adff4fcaSRuslan Ermilov 			/* NOTREACHED */
210adff4fcaSRuslan Ermilov 		}
211adff4fcaSRuslan Ermilov 		if (*unit == '\0') {
212adff4fcaSRuslan Ermilov 			errx(1, "%s: %s: missing trailing unit", option, vp);
213adff4fcaSRuslan Ermilov 			/* NOTREACHED */
214adff4fcaSRuslan Ermilov 		}
215adff4fcaSRuslan Ermilov 	}
216adff4fcaSRuslan Ermilov 	plan->flags |= F_EXACTTIME;
217adff4fcaSRuslan Ermilov 	return secs;
218adff4fcaSRuslan Ermilov }
219adff4fcaSRuslan Ermilov 
220adff4fcaSRuslan Ermilov /*
221ea92232aSPoul-Henning Kamp  * nextarg --
222ea92232aSPoul-Henning Kamp  *	Check that another argument still exists, return a pointer to it,
223ea92232aSPoul-Henning Kamp  *	and increment the argument vector pointer.
224ea92232aSPoul-Henning Kamp  */
225ea92232aSPoul-Henning Kamp static char *
226ef646f18SMark Murray nextarg(OPTION *option, char ***argvp)
227ea92232aSPoul-Henning Kamp {
228ea92232aSPoul-Henning Kamp 	char *arg;
229ea92232aSPoul-Henning Kamp 
230ea92232aSPoul-Henning Kamp 	if ((arg = **argvp) == 0)
231ea92232aSPoul-Henning Kamp 		errx(1, "%s: requires additional arguments", option->name);
232ea92232aSPoul-Henning Kamp 	(*argvp)++;
233ea92232aSPoul-Henning Kamp 	return arg;
234ea92232aSPoul-Henning Kamp } /* nextarg() */
235ea92232aSPoul-Henning Kamp 
236ea92232aSPoul-Henning Kamp /*
2379b50d902SRodney W. Grimes  * The value of n for the inode times (atime, ctime, and mtime) is a range,
2389b50d902SRodney W. Grimes  * i.e. n matches from (n - 1) to n 24 hour periods.  This interacts with
2399b50d902SRodney W. Grimes  * -n, such that "-mtime -1" would be less than 0 days, which isn't what the
2409b50d902SRodney W. Grimes  * user wanted.  Correct so that -1 is "less than 1".
2419b50d902SRodney W. Grimes  */
242ea92232aSPoul-Henning Kamp #define	TIME_CORRECT(p) \
243ea92232aSPoul-Henning Kamp 	if (((p)->flags & F_ELG_MASK) == F_LESSTHAN) \
2449b50d902SRodney W. Grimes 		++((p)->t_data);
2459b50d902SRodney W. Grimes 
2469b50d902SRodney W. Grimes /*
247ea92232aSPoul-Henning Kamp  * -[acm]min n functions --
2483f5223f8SWolfram Schneider  *
249ea92232aSPoul-Henning Kamp  *    True if the difference between the
250ea92232aSPoul-Henning Kamp  *		file access time (-amin)
251ea92232aSPoul-Henning Kamp  *		last change of file status information (-cmin)
252ea92232aSPoul-Henning Kamp  *		file modification time (-mmin)
253ea92232aSPoul-Henning Kamp  *    and the current time is n min periods.
2543f5223f8SWolfram Schneider  */
2553f5223f8SWolfram Schneider int
256ef646f18SMark Murray f_Xmin(PLAN *plan, FTSENT *entry)
2573f5223f8SWolfram Schneider {
258ea92232aSPoul-Henning Kamp 	if (plan->flags & F_TIME_C) {
2593f5223f8SWolfram Schneider 		COMPARE((now - entry->fts_statp->st_ctime +
2603f5223f8SWolfram Schneider 		    60 - 1) / 60, plan->t_data);
261ea92232aSPoul-Henning Kamp 	} else if (plan->flags & F_TIME_A) {
262ea92232aSPoul-Henning Kamp 		COMPARE((now - entry->fts_statp->st_atime +
263ea92232aSPoul-Henning Kamp 		    60 - 1) / 60, plan->t_data);
264ea92232aSPoul-Henning Kamp 	} else {
265ea92232aSPoul-Henning Kamp 		COMPARE((now - entry->fts_statp->st_mtime +
266ea92232aSPoul-Henning Kamp 		    60 - 1) / 60, plan->t_data);
267ea92232aSPoul-Henning Kamp 	}
2683f5223f8SWolfram Schneider }
2693f5223f8SWolfram Schneider 
2703f5223f8SWolfram Schneider PLAN *
271ef646f18SMark Murray c_Xmin(OPTION *option, char ***argvp)
2723f5223f8SWolfram Schneider {
273ea92232aSPoul-Henning Kamp 	char *nmins;
2743f5223f8SWolfram Schneider 	PLAN *new;
2753f5223f8SWolfram Schneider 
276ea92232aSPoul-Henning Kamp 	nmins = nextarg(option, argvp);
2773f5223f8SWolfram Schneider 	ftsoptions &= ~FTS_NOSTAT;
2783f5223f8SWolfram Schneider 
279ea92232aSPoul-Henning Kamp 	new = palloc(option);
280ea92232aSPoul-Henning Kamp 	new->t_data = find_parsenum(new, option->name, nmins, NULL);
281ea92232aSPoul-Henning Kamp 	TIME_CORRECT(new);
282ea92232aSPoul-Henning Kamp 	return new;
2833f5223f8SWolfram Schneider }
2843f5223f8SWolfram Schneider 
2859b50d902SRodney W. Grimes /*
286ea92232aSPoul-Henning Kamp  * -[acm]time n functions --
2879b50d902SRodney W. Grimes  *
288ea92232aSPoul-Henning Kamp  *	True if the difference between the
289ea92232aSPoul-Henning Kamp  *		file access time (-atime)
290ea92232aSPoul-Henning Kamp  *		last change of file status information (-ctime)
291ea92232aSPoul-Henning Kamp  *		file modification time (-mtime)
292ea92232aSPoul-Henning Kamp  *	and the current time is n 24 hour periods.
2939b50d902SRodney W. Grimes  */
294ea92232aSPoul-Henning Kamp 
2959b50d902SRodney W. Grimes int
296ef646f18SMark Murray f_Xtime(PLAN *plan, FTSENT *entry)
2979b50d902SRodney W. Grimes {
298631a8765SRuslan Ermilov 	time_t xtime;
299adff4fcaSRuslan Ermilov 
300631a8765SRuslan Ermilov 	if (plan->flags & F_TIME_A)
301631a8765SRuslan Ermilov 		xtime = entry->fts_statp->st_atime;
302631a8765SRuslan Ermilov 	else if (plan->flags & F_TIME_C)
303631a8765SRuslan Ermilov 		xtime = entry->fts_statp->st_ctime;
304631a8765SRuslan Ermilov 	else
305631a8765SRuslan Ermilov 		xtime = entry->fts_statp->st_mtime;
3069b50d902SRodney W. Grimes 
307631a8765SRuslan Ermilov 	if (plan->flags & F_EXACTTIME)
308631a8765SRuslan Ermilov 		COMPARE(now - xtime, plan->t_data);
309adff4fcaSRuslan Ermilov 	else
310631a8765SRuslan Ermilov 		COMPARE((now - xtime + 86400 - 1) / 86400, plan->t_data);
3119b50d902SRodney W. Grimes }
3129b50d902SRodney W. Grimes 
3139b50d902SRodney W. Grimes PLAN *
314ef646f18SMark Murray c_Xtime(OPTION *option, char ***argvp)
3159b50d902SRodney W. Grimes {
316adff4fcaSRuslan Ermilov 	char *value;
3179b50d902SRodney W. Grimes 	PLAN *new;
3189b50d902SRodney W. Grimes 
319adff4fcaSRuslan Ermilov 	value = nextarg(option, argvp);
3209b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_NOSTAT;
3219b50d902SRodney W. Grimes 
322ea92232aSPoul-Henning Kamp 	new = palloc(option);
323adff4fcaSRuslan Ermilov 	new->t_data = find_parsetime(new, option->name, value);
324adff4fcaSRuslan Ermilov 	if (!(new->flags & F_EXACTTIME))
325ea92232aSPoul-Henning Kamp 		TIME_CORRECT(new);
326ea92232aSPoul-Henning Kamp 	return new;
327ea92232aSPoul-Henning Kamp }
328ea92232aSPoul-Henning Kamp 
329ea92232aSPoul-Henning Kamp /*
330ea92232aSPoul-Henning Kamp  * -maxdepth/-mindepth n functions --
331ea92232aSPoul-Henning Kamp  *
332ea92232aSPoul-Henning Kamp  *        Does the same as -prune if the level of the current file is
333ea92232aSPoul-Henning Kamp  *        greater/less than the specified maximum/minimum depth.
334ea92232aSPoul-Henning Kamp  *
335ea92232aSPoul-Henning Kamp  *        Note that -maxdepth and -mindepth are handled specially in
336ea92232aSPoul-Henning Kamp  *        find_execute() so their f_* functions are set to f_always_true().
337ea92232aSPoul-Henning Kamp  */
338ea92232aSPoul-Henning Kamp PLAN *
339ef646f18SMark Murray c_mXXdepth(OPTION *option, char ***argvp)
340ea92232aSPoul-Henning Kamp {
341ea92232aSPoul-Henning Kamp 	char *dstr;
342ea92232aSPoul-Henning Kamp 	PLAN *new;
343ea92232aSPoul-Henning Kamp 
344ea92232aSPoul-Henning Kamp 	dstr = nextarg(option, argvp);
345ea92232aSPoul-Henning Kamp 	if (dstr[0] == '-')
346ea92232aSPoul-Henning Kamp 		/* all other errors handled by find_parsenum() */
347ea92232aSPoul-Henning Kamp 		errx(1, "%s: %s: value must be positive", option->name, dstr);
348ea92232aSPoul-Henning Kamp 
349ea92232aSPoul-Henning Kamp 	new = palloc(option);
350ea92232aSPoul-Henning Kamp 	if (option->flags & F_MAXDEPTH)
351ea92232aSPoul-Henning Kamp 		maxdepth = find_parsenum(new, option->name, dstr, NULL);
352ea92232aSPoul-Henning Kamp 	else
353ea92232aSPoul-Henning Kamp 		mindepth = find_parsenum(new, option->name, dstr, NULL);
354ea92232aSPoul-Henning Kamp 	return new;
355ea92232aSPoul-Henning Kamp }
356ea92232aSPoul-Henning Kamp 
357ea92232aSPoul-Henning Kamp /*
3589c5d31dfSBosko Milekic  * -acl function --
3599c5d31dfSBosko Milekic  *
3609c5d31dfSBosko Milekic  *	Show files with EXTENDED ACL attributes.
3619c5d31dfSBosko Milekic  */
3629c5d31dfSBosko Milekic int
3639c5d31dfSBosko Milekic f_acl(PLAN *plan __unused, FTSENT *entry)
3649c5d31dfSBosko Milekic {
3659c5d31dfSBosko Milekic 	int match, entries;
3669c5d31dfSBosko Milekic 	acl_entry_t ae;
3679c5d31dfSBosko Milekic 	acl_t facl;
3689c5d31dfSBosko Milekic 
3699c5d31dfSBosko Milekic 	if (S_ISLNK(entry->fts_statp->st_mode))
3709c5d31dfSBosko Milekic 		return 0;
3719c5d31dfSBosko Milekic 	if ((match = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED)) <= 0) {
3729c5d31dfSBosko Milekic 		if (match < 0 && errno != EINVAL)
3739c5d31dfSBosko Milekic 			warn("%s", entry->fts_accpath);
3749c5d31dfSBosko Milekic 	else
3759c5d31dfSBosko Milekic 		return 0;
3769c5d31dfSBosko Milekic 	}
3779c5d31dfSBosko Milekic 	match = 0;
3789c5d31dfSBosko Milekic 	if ((facl = acl_get_file(entry->fts_accpath,ACL_TYPE_ACCESS)) != NULL) {
3799c5d31dfSBosko Milekic 		if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) {
3809c5d31dfSBosko Milekic 			/*
3819c5d31dfSBosko Milekic 			 * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS
3829c5d31dfSBosko Milekic 			 * must have at least three entries (owner, group,
3839c5d31dfSBosko Milekic 			 * other).
3849c5d31dfSBosko Milekic 			 */
3859c5d31dfSBosko Milekic 			entries = 1;
3869c5d31dfSBosko Milekic 			while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1) {
3879c5d31dfSBosko Milekic 				if (++entries > 3) {
3889c5d31dfSBosko Milekic 					match = 1;
3899c5d31dfSBosko Milekic 					break;
3909c5d31dfSBosko Milekic 				}
3919c5d31dfSBosko Milekic 			}
3929c5d31dfSBosko Milekic 		}
3939c5d31dfSBosko Milekic 		acl_free(facl);
3949c5d31dfSBosko Milekic 	} else
3959c5d31dfSBosko Milekic 		warn("%s", entry->fts_accpath);
3969c5d31dfSBosko Milekic 	return match;
3979c5d31dfSBosko Milekic }
3989c5d31dfSBosko Milekic 
3999c5d31dfSBosko Milekic PLAN *
4009c5d31dfSBosko Milekic c_acl(OPTION *option, char ***argvp __unused)
4019c5d31dfSBosko Milekic {
4029c5d31dfSBosko Milekic 	ftsoptions &= ~FTS_NOSTAT;
4039c5d31dfSBosko Milekic 	return (palloc(option));
4049c5d31dfSBosko Milekic }
4059c5d31dfSBosko Milekic 
4069c5d31dfSBosko Milekic /*
407ea92232aSPoul-Henning Kamp  * -delete functions --
408ea92232aSPoul-Henning Kamp  *
409ea92232aSPoul-Henning Kamp  *	True always.  Makes its best shot and continues on regardless.
410ea92232aSPoul-Henning Kamp  */
411ea92232aSPoul-Henning Kamp int
412ef646f18SMark Murray f_delete(PLAN *plan __unused, FTSENT *entry)
413ea92232aSPoul-Henning Kamp {
414ea92232aSPoul-Henning Kamp 	/* ignore these from fts */
415ea92232aSPoul-Henning Kamp 	if (strcmp(entry->fts_accpath, ".") == 0 ||
416ea92232aSPoul-Henning Kamp 	    strcmp(entry->fts_accpath, "..") == 0)
417ea92232aSPoul-Henning Kamp 		return 1;
418ea92232aSPoul-Henning Kamp 
419ea92232aSPoul-Henning Kamp 	/* sanity check */
420ea92232aSPoul-Henning Kamp 	if (isdepth == 0 ||			/* depth off */
421ea92232aSPoul-Henning Kamp 	    (ftsoptions & FTS_NOSTAT) ||	/* not stat()ing */
422ea92232aSPoul-Henning Kamp 	    !(ftsoptions & FTS_PHYSICAL) ||	/* physical off */
423ea92232aSPoul-Henning Kamp 	    (ftsoptions & FTS_LOGICAL))		/* or finally, logical on */
424ea92232aSPoul-Henning Kamp 		errx(1, "-delete: insecure options got turned on");
425ea92232aSPoul-Henning Kamp 
426ea92232aSPoul-Henning Kamp 	/* Potentially unsafe - do not accept relative paths whatsoever */
427ea92232aSPoul-Henning Kamp 	if (strchr(entry->fts_accpath, '/') != NULL)
428ea92232aSPoul-Henning Kamp 		errx(1, "-delete: %s: relative path potentially not safe",
429ea92232aSPoul-Henning Kamp 			entry->fts_accpath);
430ea92232aSPoul-Henning Kamp 
431ea92232aSPoul-Henning Kamp 	/* Turn off user immutable bits if running as root */
432ea92232aSPoul-Henning Kamp 	if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
433ea92232aSPoul-Henning Kamp 	    !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
434ea92232aSPoul-Henning Kamp 	    geteuid() == 0)
435ea92232aSPoul-Henning Kamp 		chflags(entry->fts_accpath,
436ea92232aSPoul-Henning Kamp 		       entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
437ea92232aSPoul-Henning Kamp 
438ea92232aSPoul-Henning Kamp 	/* rmdir directories, unlink everything else */
439ea92232aSPoul-Henning Kamp 	if (S_ISDIR(entry->fts_statp->st_mode)) {
440ea92232aSPoul-Henning Kamp 		if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
441ea92232aSPoul-Henning Kamp 			warn("-delete: rmdir(%s)", entry->fts_path);
442ea92232aSPoul-Henning Kamp 	} else {
443ea92232aSPoul-Henning Kamp 		if (unlink(entry->fts_accpath) < 0)
444ea92232aSPoul-Henning Kamp 			warn("-delete: unlink(%s)", entry->fts_path);
445ea92232aSPoul-Henning Kamp 	}
446ea92232aSPoul-Henning Kamp 
447ea92232aSPoul-Henning Kamp 	/* "succeed" */
448ea92232aSPoul-Henning Kamp 	return 1;
449ea92232aSPoul-Henning Kamp }
450ea92232aSPoul-Henning Kamp 
451ea92232aSPoul-Henning Kamp PLAN *
452ef646f18SMark Murray c_delete(OPTION *option, char ***argvp __unused)
453ea92232aSPoul-Henning Kamp {
454ea92232aSPoul-Henning Kamp 
455ea92232aSPoul-Henning Kamp 	ftsoptions &= ~FTS_NOSTAT;	/* no optimise */
456ea92232aSPoul-Henning Kamp 	ftsoptions |= FTS_PHYSICAL;	/* disable -follow */
457ea92232aSPoul-Henning Kamp 	ftsoptions &= ~FTS_LOGICAL;	/* disable -follow */
458ea92232aSPoul-Henning Kamp 	isoutput = 1;			/* possible output */
459ea92232aSPoul-Henning Kamp 	isdepth = 1;			/* -depth implied */
460ea92232aSPoul-Henning Kamp 
461ea92232aSPoul-Henning Kamp 	return palloc(option);
4629b50d902SRodney W. Grimes }
4639b50d902SRodney W. Grimes 
4643f5223f8SWolfram Schneider 
4659b50d902SRodney W. Grimes /*
4661c832963SOliver Eikemeier  * always_true --
4679b50d902SRodney W. Grimes  *
4681c832963SOliver Eikemeier  *	Always true, used for -maxdepth, -mindepth, -xdev and -follow
4699b50d902SRodney W. Grimes  */
4709b50d902SRodney W. Grimes int
471ef646f18SMark Murray f_always_true(PLAN *plan __unused, FTSENT *entry __unused)
4729b50d902SRodney W. Grimes {
473ea92232aSPoul-Henning Kamp 	return 1;
4749b50d902SRodney W. Grimes }
4759b50d902SRodney W. Grimes 
4761c832963SOliver Eikemeier /*
4771c832963SOliver Eikemeier  * -depth functions --
4781c832963SOliver Eikemeier  *
4791c832963SOliver Eikemeier  *	With argument: True if the file is at level n.
4801c832963SOliver Eikemeier  *	Without argument: Always true, causes descent of the directory hierarchy
4811c832963SOliver Eikemeier  *	to be done so that all entries in a directory are acted on before the
4821c832963SOliver Eikemeier  *	directory itself.
4831c832963SOliver Eikemeier  */
4841c832963SOliver Eikemeier int
4851c832963SOliver Eikemeier f_depth(PLAN *plan, FTSENT *entry)
4869b50d902SRodney W. Grimes {
4871c832963SOliver Eikemeier 	if (plan->flags & F_DEPTH)
4881c832963SOliver Eikemeier 		COMPARE(entry->fts_level, plan->d_data);
4891c832963SOliver Eikemeier 	else
4901c832963SOliver Eikemeier 		return 1;
4911c832963SOliver Eikemeier }
4929b50d902SRodney W. Grimes 
4931c832963SOliver Eikemeier PLAN *
4941c832963SOliver Eikemeier c_depth(OPTION *option, char ***argvp)
4951c832963SOliver Eikemeier {
4961c832963SOliver Eikemeier 	PLAN *new;
4971c832963SOliver Eikemeier 	char *str;
4981c832963SOliver Eikemeier 
4991c832963SOliver Eikemeier 	new = palloc(option);
5001c832963SOliver Eikemeier 
5011c832963SOliver Eikemeier 	str = **argvp;
5021c832963SOliver Eikemeier 	if (str && !(new->flags & F_DEPTH)) {
5031c832963SOliver Eikemeier 		/* skip leading + or - */
5041c832963SOliver Eikemeier 		if (*str == '+' || *str == '-')
5051c832963SOliver Eikemeier 			str++;
5061c832963SOliver Eikemeier 		/* skip sign */
5071c832963SOliver Eikemeier 		if (*str == '+' || *str == '-')
5081c832963SOliver Eikemeier 			str++;
5091c832963SOliver Eikemeier 		if (isdigit(*str))
5101c832963SOliver Eikemeier 			new->flags |= F_DEPTH;
5111c832963SOliver Eikemeier 	}
5121c832963SOliver Eikemeier 
5131c832963SOliver Eikemeier 	if (new->flags & F_DEPTH) {	/* -depth n */
5141c832963SOliver Eikemeier 		char *ndepth;
5151c832963SOliver Eikemeier 
5161c832963SOliver Eikemeier 		ndepth = nextarg(option, argvp);
5171c832963SOliver Eikemeier 		new->d_data = find_parsenum(new, option->name, ndepth, NULL);
5181c832963SOliver Eikemeier 	} else {			/* -d */
5191c832963SOliver Eikemeier 		isdepth = 1;
5201c832963SOliver Eikemeier 	}
5211c832963SOliver Eikemeier 
5221c832963SOliver Eikemeier 	return new;
5239b50d902SRodney W. Grimes }
524127d7563SWarner Losh 
525127d7563SWarner Losh /*
526ed1a4621SPeter Wemm  * -empty functions --
527ed1a4621SPeter Wemm  *
528ed1a4621SPeter Wemm  *	True if the file or directory is empty
529ed1a4621SPeter Wemm  */
530ed1a4621SPeter Wemm int
531ef646f18SMark Murray f_empty(PLAN *plan __unused, FTSENT *entry)
532ed1a4621SPeter Wemm {
533ea92232aSPoul-Henning Kamp 	if (S_ISREG(entry->fts_statp->st_mode) &&
534ea92232aSPoul-Henning Kamp 	    entry->fts_statp->st_size == 0)
535ea92232aSPoul-Henning Kamp 		return 1;
536ed1a4621SPeter Wemm 	if (S_ISDIR(entry->fts_statp->st_mode)) {
537ed1a4621SPeter Wemm 		struct dirent *dp;
538ed1a4621SPeter Wemm 		int empty;
539ed1a4621SPeter Wemm 		DIR *dir;
540ed1a4621SPeter Wemm 
541ed1a4621SPeter Wemm 		empty = 1;
542ed1a4621SPeter Wemm 		dir = opendir(entry->fts_accpath);
543ed1a4621SPeter Wemm 		if (dir == NULL)
544ed1a4621SPeter Wemm 			err(1, "%s", entry->fts_accpath);
545ed1a4621SPeter Wemm 		for (dp = readdir(dir); dp; dp = readdir(dir))
546ed1a4621SPeter Wemm 			if (dp->d_name[0] != '.' ||
547ed1a4621SPeter Wemm 			    (dp->d_name[1] != '\0' &&
548ed1a4621SPeter Wemm 			     (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) {
549ed1a4621SPeter Wemm 				empty = 0;
550ed1a4621SPeter Wemm 				break;
551ed1a4621SPeter Wemm 			}
552ed1a4621SPeter Wemm 		closedir(dir);
553ea92232aSPoul-Henning Kamp 		return empty;
554ed1a4621SPeter Wemm 	}
555ea92232aSPoul-Henning Kamp 	return 0;
556ed1a4621SPeter Wemm }
557ed1a4621SPeter Wemm 
558ed1a4621SPeter Wemm PLAN *
559ef646f18SMark Murray c_empty(OPTION *option, char ***argvp __unused)
560ed1a4621SPeter Wemm {
561ed1a4621SPeter Wemm 	ftsoptions &= ~FTS_NOSTAT;
562ed1a4621SPeter Wemm 
563ea92232aSPoul-Henning Kamp 	return palloc(option);
564ed1a4621SPeter Wemm }
565ed1a4621SPeter Wemm 
566ed1a4621SPeter Wemm /*
567ea92232aSPoul-Henning Kamp  * [-exec | -execdir | -ok] utility [arg ... ] ; functions --
568127d7563SWarner Losh  *
569127d7563SWarner Losh  *	True if the executed utility returns a zero value as exit status.
570127d7563SWarner Losh  *	The end of the primary expression is delimited by a semicolon.  If
571ea92232aSPoul-Henning Kamp  *	"{}" occurs anywhere, it gets replaced by the current pathname,
572ea92232aSPoul-Henning Kamp  *	or, in the case of -execdir, the current basename (filename
573ea92232aSPoul-Henning Kamp  *	without leading directory prefix). For -exec and -ok,
574ea92232aSPoul-Henning Kamp  *	the current directory for the execution of utility is the same as
575ea92232aSPoul-Henning Kamp  *	the current directory when the find utility was started, whereas
576ea92232aSPoul-Henning Kamp  *	for -execdir, it is the directory the file resides in.
577ea92232aSPoul-Henning Kamp  *
578ea92232aSPoul-Henning Kamp  *	The primary -ok differs from -exec in that it requests affirmation
579ea92232aSPoul-Henning Kamp  *	of the user before executing the utility.
580127d7563SWarner Losh  */
581127d7563SWarner Losh int
582ef646f18SMark Murray f_exec(PLAN *plan, FTSENT *entry)
583127d7563SWarner Losh {
584e98080b1SDavid Malone 	int cnt;
585127d7563SWarner Losh 	pid_t pid;
586127d7563SWarner Losh 	int status;
587127d7563SWarner Losh 	char *file;
588127d7563SWarner Losh 
5895e25d888STim J. Robbins 	if (entry == NULL && plan->flags & F_EXECPLUS) {
5905e25d888STim J. Robbins 		if (plan->e_ppos == plan->e_pbnum)
5915e25d888STim J. Robbins 			return (1);
5925e25d888STim J. Robbins 		plan->e_argv[plan->e_ppos] = NULL;
5935e25d888STim J. Robbins 		goto doexec;
5945e25d888STim J. Robbins 	}
5955e25d888STim J. Robbins 
596127d7563SWarner Losh 	/* XXX - if file/dir ends in '/' this will not work -- can it? */
597ea92232aSPoul-Henning Kamp 	if ((plan->flags & F_EXECDIR) && \
598ea92232aSPoul-Henning Kamp 	    (file = strrchr(entry->fts_path, '/')))
599127d7563SWarner Losh 		file++;
600127d7563SWarner Losh 	else
601127d7563SWarner Losh 		file = entry->fts_path;
602127d7563SWarner Losh 
6035e25d888STim J. Robbins 	if (plan->flags & F_EXECPLUS) {
6045e25d888STim J. Robbins 		if ((plan->e_argv[plan->e_ppos] = strdup(file)) == NULL)
6055e25d888STim J. Robbins 			err(1, NULL);
6065e25d888STim J. Robbins 		plan->e_len[plan->e_ppos] = strlen(file);
6075e25d888STim J. Robbins 		plan->e_psize += plan->e_len[plan->e_ppos];
6085e25d888STim J. Robbins 		if (++plan->e_ppos < plan->e_pnummax &&
6095e25d888STim J. Robbins 		    plan->e_psize < plan->e_psizemax)
6105e25d888STim J. Robbins 			return (1);
6115e25d888STim J. Robbins 		plan->e_argv[plan->e_ppos] = NULL;
6125e25d888STim J. Robbins 	} else {
613127d7563SWarner Losh 		for (cnt = 0; plan->e_argv[cnt]; ++cnt)
614127d7563SWarner Losh 			if (plan->e_len[cnt])
6155e25d888STim J. Robbins 				brace_subst(plan->e_orig[cnt],
6165e25d888STim J. Robbins 				    &plan->e_argv[cnt], file,
6175e25d888STim J. Robbins 				    plan->e_len[cnt]);
6185e25d888STim J. Robbins 	}
619127d7563SWarner Losh 
6205e25d888STim J. Robbins doexec:	if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
621ea92232aSPoul-Henning Kamp 		return 0;
622ea92232aSPoul-Henning Kamp 
623ea92232aSPoul-Henning Kamp 	/* make sure find output is interspersed correctly with subprocesses */
624127d7563SWarner Losh 	fflush(stdout);
625127d7563SWarner Losh 	fflush(stderr);
626127d7563SWarner Losh 
6271fd98d7dSDag-Erling Smørgrav 	switch (pid = fork()) {
628127d7563SWarner Losh 	case -1:
629127d7563SWarner Losh 		err(1, "fork");
630127d7563SWarner Losh 		/* NOTREACHED */
631127d7563SWarner Losh 	case 0:
632ea92232aSPoul-Henning Kamp 		/* change dir back from where we started */
633ea92232aSPoul-Henning Kamp 		if (!(plan->flags & F_EXECDIR) && fchdir(dotfd)) {
634ea92232aSPoul-Henning Kamp 			warn("chdir");
635ea92232aSPoul-Henning Kamp 			_exit(1);
636ea92232aSPoul-Henning Kamp 		}
637127d7563SWarner Losh 		execvp(plan->e_argv[0], plan->e_argv);
638127d7563SWarner Losh 		warn("%s", plan->e_argv[0]);
639127d7563SWarner Losh 		_exit(1);
640127d7563SWarner Losh 	}
6415e25d888STim J. Robbins 	if (plan->flags & F_EXECPLUS) {
6425e25d888STim J. Robbins 		while (--plan->e_ppos >= plan->e_pbnum)
6435e25d888STim J. Robbins 			free(plan->e_argv[plan->e_ppos]);
6445e25d888STim J. Robbins 		plan->e_ppos = plan->e_pbnum;
6455e25d888STim J. Robbins 		plan->e_psize = plan->e_pbsize;
6465e25d888STim J. Robbins 	}
647127d7563SWarner Losh 	pid = waitpid(pid, &status, 0);
648127d7563SWarner Losh 	return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
649127d7563SWarner Losh }
650127d7563SWarner Losh 
651127d7563SWarner Losh /*
652ea92232aSPoul-Henning Kamp  * c_exec, c_execdir, c_ok --
653127d7563SWarner Losh  *	build three parallel arrays, one with pointers to the strings passed
654127d7563SWarner Losh  *	on the command line, one with (possibly duplicated) pointers to the
655127d7563SWarner Losh  *	argv array, and one with integer values that are lengths of the
656127d7563SWarner Losh  *	strings, but also flags meaning that the string has to be massaged.
657127d7563SWarner Losh  */
658127d7563SWarner Losh PLAN *
659ef646f18SMark Murray c_exec(OPTION *option, char ***argvp)
660127d7563SWarner Losh {
661127d7563SWarner Losh 	PLAN *new;			/* node returned */
6625e25d888STim J. Robbins 	long argmax;
6635e25d888STim J. Robbins 	int cnt, i;
664a07af811STim J. Robbins 	char **argv, **ap, **ep, *p;
665127d7563SWarner Losh 
666ea92232aSPoul-Henning Kamp 	/* XXX - was in c_execdir, but seems unnecessary!?
667127d7563SWarner Losh 	ftsoptions &= ~FTS_NOSTAT;
668ea92232aSPoul-Henning Kamp 	*/
669127d7563SWarner Losh 	isoutput = 1;
670127d7563SWarner Losh 
671ea92232aSPoul-Henning Kamp 	/* XXX - this is a change from the previous coding */
672ea92232aSPoul-Henning Kamp 	new = palloc(option);
673127d7563SWarner Losh 
674127d7563SWarner Losh 	for (ap = argv = *argvp;; ++ap) {
675127d7563SWarner Losh 		if (!*ap)
676127d7563SWarner Losh 			errx(1,
677e22bb9dbSTim J. Robbins 			    "%s: no terminating \";\" or \"+\"", option->name);
678127d7563SWarner Losh 		if (**ap == ';')
679127d7563SWarner Losh 			break;
6805e25d888STim J. Robbins 		if (**ap == '+' && ap != argv && strcmp(*(ap - 1), "{}") == 0) {
6815e25d888STim J. Robbins 			new->flags |= F_EXECPLUS;
6825e25d888STim J. Robbins 			break;
6835e25d888STim J. Robbins 		}
684127d7563SWarner Losh 	}
685127d7563SWarner Losh 
68651b0534fSJuli Mallett 	if (ap == argv)
68751b0534fSJuli Mallett 		errx(1, "%s: no command specified", option->name);
68851b0534fSJuli Mallett 
689127d7563SWarner Losh 	cnt = ap - *argvp + 1;
6905e25d888STim J. Robbins 	if (new->flags & F_EXECPLUS) {
6915e25d888STim J. Robbins 		new->e_ppos = new->e_pbnum = cnt - 2;
6925e25d888STim J. Robbins 		if ((argmax = sysconf(_SC_ARG_MAX)) == -1) {
6935e25d888STim J. Robbins 			warn("sysconf(_SC_ARG_MAX)");
6945e25d888STim J. Robbins 			argmax = _POSIX_ARG_MAX;
6955e25d888STim J. Robbins 		}
696a07af811STim J. Robbins 		argmax -= 1024;
697a07af811STim J. Robbins 		for (ep = environ; *ep != NULL; ep++)
698a07af811STim J. Robbins 			argmax -= strlen(*ep) + 1 + sizeof(*ep);
699a07af811STim J. Robbins 		argmax -= 1 + sizeof(*ep);
700a07af811STim J. Robbins 		new->e_pnummax = argmax / 16;
701a07af811STim J. Robbins 		argmax -= sizeof(char *) * new->e_pnummax;
702a07af811STim J. Robbins 		if (argmax <= 0)
703a07af811STim J. Robbins 			errx(1, "no space for arguments");
704a07af811STim J. Robbins 		new->e_psizemax = argmax;
7055e25d888STim J. Robbins 		new->e_pbsize = 0;
7065e25d888STim J. Robbins 		cnt += new->e_pnummax + 1;
7075e25d888STim J. Robbins 	}
70847bca8b0SJuli Mallett 	if ((new->e_argv = malloc(cnt * sizeof(char *))) == NULL)
70947bca8b0SJuli Mallett 		err(1, NULL);
71047bca8b0SJuli Mallett 	if ((new->e_orig = malloc(cnt * sizeof(char *))) == NULL)
71147bca8b0SJuli Mallett 		err(1, NULL);
71247bca8b0SJuli Mallett 	if ((new->e_len = malloc(cnt * sizeof(int))) == NULL)
71347bca8b0SJuli Mallett 		err(1, NULL);
714127d7563SWarner Losh 
715127d7563SWarner Losh 	for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
716127d7563SWarner Losh 		new->e_orig[cnt] = *argv;
7175e25d888STim J. Robbins 		if (new->flags & F_EXECPLUS)
7185e25d888STim J. Robbins 			new->e_pbsize += strlen(*argv) + 1;
719127d7563SWarner Losh 		for (p = *argv; *p; ++p)
7205e25d888STim J. Robbins 			if (!(new->flags & F_EXECPLUS) && p[0] == '{' &&
7215e25d888STim J. Robbins 			    p[1] == '}') {
722f0cb9537SDavid E. O'Brien 				if ((new->e_argv[cnt] =
72347bca8b0SJuli Mallett 				    malloc(MAXPATHLEN)) == NULL)
72447bca8b0SJuli Mallett 					err(1, NULL);
725127d7563SWarner Losh 				new->e_len[cnt] = MAXPATHLEN;
726127d7563SWarner Losh 				break;
727127d7563SWarner Losh 			}
728127d7563SWarner Losh 		if (!*p) {
729127d7563SWarner Losh 			new->e_argv[cnt] = *argv;
730127d7563SWarner Losh 			new->e_len[cnt] = 0;
731127d7563SWarner Losh 		}
732127d7563SWarner Losh 	}
7335e25d888STim J. Robbins 	if (new->flags & F_EXECPLUS) {
7345e25d888STim J. Robbins 		new->e_psize = new->e_pbsize;
7355e25d888STim J. Robbins 		cnt--;
7365e25d888STim J. Robbins 		for (i = 0; i < new->e_pnummax; i++) {
7375e25d888STim J. Robbins 			new->e_argv[cnt] = NULL;
7385e25d888STim J. Robbins 			new->e_len[cnt] = 0;
7395e25d888STim J. Robbins 			cnt++;
7405e25d888STim J. Robbins 		}
7415e25d888STim J. Robbins 		argv = ap;
7425e25d888STim J. Robbins 		goto done;
7435e25d888STim J. Robbins 	}
744127d7563SWarner Losh 	new->e_argv[cnt] = new->e_orig[cnt] = NULL;
745127d7563SWarner Losh 
7465e25d888STim J. Robbins done:	*argvp = argv + 1;
747ea92232aSPoul-Henning Kamp 	return new;
748ea92232aSPoul-Henning Kamp }
749ea92232aSPoul-Henning Kamp 
750ea92232aSPoul-Henning Kamp int
751ef646f18SMark Murray f_flags(PLAN *plan, FTSENT *entry)
752ea92232aSPoul-Henning Kamp {
753ea92232aSPoul-Henning Kamp 	u_long flags;
754ea92232aSPoul-Henning Kamp 
7557fd5ee41SRuslan Ermilov 	flags = entry->fts_statp->st_flags;
756ea92232aSPoul-Henning Kamp 	if (plan->flags & F_ATLEAST)
7577fd5ee41SRuslan Ermilov 		return (flags | plan->fl_flags) == flags &&
7587fd5ee41SRuslan Ermilov 		    !(flags & plan->fl_notflags);
7597fd5ee41SRuslan Ermilov 	else if (plan->flags & F_ANY)
7607fd5ee41SRuslan Ermilov 		return (flags & plan->fl_flags) ||
7617fd5ee41SRuslan Ermilov 		    (flags | plan->fl_notflags) != flags;
762ea92232aSPoul-Henning Kamp 	else
7637fd5ee41SRuslan Ermilov 		return flags == plan->fl_flags &&
7647fd5ee41SRuslan Ermilov 		    !(plan->fl_flags & plan->fl_notflags);
765ea92232aSPoul-Henning Kamp }
766ea92232aSPoul-Henning Kamp 
767ea92232aSPoul-Henning Kamp PLAN *
768ef646f18SMark Murray c_flags(OPTION *option, char ***argvp)
769ea92232aSPoul-Henning Kamp {
770ea92232aSPoul-Henning Kamp 	char *flags_str;
771ea92232aSPoul-Henning Kamp 	PLAN *new;
772ea92232aSPoul-Henning Kamp 	u_long flags, notflags;
773ea92232aSPoul-Henning Kamp 
774ea92232aSPoul-Henning Kamp 	flags_str = nextarg(option, argvp);
775ea92232aSPoul-Henning Kamp 	ftsoptions &= ~FTS_NOSTAT;
776ea92232aSPoul-Henning Kamp 
777ea92232aSPoul-Henning Kamp 	new = palloc(option);
778ea92232aSPoul-Henning Kamp 
779ea92232aSPoul-Henning Kamp 	if (*flags_str == '-') {
780ea92232aSPoul-Henning Kamp 		new->flags |= F_ATLEAST;
781ea92232aSPoul-Henning Kamp 		flags_str++;
7827fd5ee41SRuslan Ermilov 	} else if (*flags_str == '+') {
7837fd5ee41SRuslan Ermilov 		new->flags |= F_ANY;
7847fd5ee41SRuslan Ermilov 		flags_str++;
785ea92232aSPoul-Henning Kamp 	}
786ea92232aSPoul-Henning Kamp 	if (strtofflags(&flags_str, &flags, &notflags) == 1)
787ea92232aSPoul-Henning Kamp 		errx(1, "%s: %s: illegal flags string", option->name, flags_str);
788ea92232aSPoul-Henning Kamp 
789ea92232aSPoul-Henning Kamp 	new->fl_flags = flags;
7907fd5ee41SRuslan Ermilov 	new->fl_notflags = notflags;
791ea92232aSPoul-Henning Kamp 	return new;
792127d7563SWarner Losh }
7939b50d902SRodney W. Grimes 
7949b50d902SRodney W. Grimes /*
7959b50d902SRodney W. Grimes  * -follow functions --
7969b50d902SRodney W. Grimes  *
7979b50d902SRodney W. Grimes  *	Always true, causes symbolic links to be followed on a global
7989b50d902SRodney W. Grimes  *	basis.
7999b50d902SRodney W. Grimes  */
8009b50d902SRodney W. Grimes PLAN *
801ef646f18SMark Murray c_follow(OPTION *option, char ***argvp __unused)
8029b50d902SRodney W. Grimes {
8039b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_PHYSICAL;
8049b50d902SRodney W. Grimes 	ftsoptions |= FTS_LOGICAL;
8059b50d902SRodney W. Grimes 
806ea92232aSPoul-Henning Kamp 	return palloc(option);
8079b50d902SRodney W. Grimes }
8089b50d902SRodney W. Grimes 
8099b50d902SRodney W. Grimes /*
8109b50d902SRodney W. Grimes  * -fstype functions --
8119b50d902SRodney W. Grimes  *
8129b50d902SRodney W. Grimes  *	True if the file is of a certain type.
8139b50d902SRodney W. Grimes  */
8149b50d902SRodney W. Grimes int
815ef646f18SMark Murray f_fstype(PLAN *plan, FTSENT *entry)
8169b50d902SRodney W. Grimes {
8179b50d902SRodney W. Grimes 	static dev_t curdev;	/* need a guaranteed illegal dev value */
8189b50d902SRodney W. Grimes 	static int first = 1;
8199b50d902SRodney W. Grimes 	struct statfs sb;
8209d08e419SPeter Wemm 	static int val_type, val_flags;
8218a0a76b8SOllivier Robert 	char *p, save[2] = {0,0};
8229b50d902SRodney W. Grimes 
823ea92232aSPoul-Henning Kamp 	if ((plan->flags & F_MTMASK) == F_MTUNKNOWN)
824ea92232aSPoul-Henning Kamp 		return 0;
825ea92232aSPoul-Henning Kamp 
8269b50d902SRodney W. Grimes 	/* Only check when we cross mount point. */
8279b50d902SRodney W. Grimes 	if (first || curdev != entry->fts_statp->st_dev) {
8289b50d902SRodney W. Grimes 		curdev = entry->fts_statp->st_dev;
8299b50d902SRodney W. Grimes 
8309b50d902SRodney W. Grimes 		/*
8319b50d902SRodney W. Grimes 		 * Statfs follows symlinks; find wants the link's filesystem,
8329b50d902SRodney W. Grimes 		 * not where it points.
8339b50d902SRodney W. Grimes 		 */
8349b50d902SRodney W. Grimes 		if (entry->fts_info == FTS_SL ||
8359b50d902SRodney W. Grimes 		    entry->fts_info == FTS_SLNONE) {
8369b50d902SRodney W. Grimes 			if ((p = strrchr(entry->fts_accpath, '/')) != NULL)
8379b50d902SRodney W. Grimes 				++p;
8389b50d902SRodney W. Grimes 			else
8399b50d902SRodney W. Grimes 				p = entry->fts_accpath;
8409b50d902SRodney W. Grimes 			save[0] = p[0];
8419b50d902SRodney W. Grimes 			p[0] = '.';
8429b50d902SRodney W. Grimes 			save[1] = p[1];
8439b50d902SRodney W. Grimes 			p[1] = '\0';
8449b50d902SRodney W. Grimes 		} else
8459b50d902SRodney W. Grimes 			p = NULL;
8469b50d902SRodney W. Grimes 
8479b50d902SRodney W. Grimes 		if (statfs(entry->fts_accpath, &sb))
8489b50d902SRodney W. Grimes 			err(1, "%s", entry->fts_accpath);
8499b50d902SRodney W. Grimes 
8509b50d902SRodney W. Grimes 		if (p) {
8519b50d902SRodney W. Grimes 			p[0] = save[0];
8529b50d902SRodney W. Grimes 			p[1] = save[1];
8539b50d902SRodney W. Grimes 		}
8549b50d902SRodney W. Grimes 
8559b50d902SRodney W. Grimes 		first = 0;
856841484cdSPeter Wemm 
857841484cdSPeter Wemm 		/*
858841484cdSPeter Wemm 		 * Further tests may need both of these values, so
859841484cdSPeter Wemm 		 * always copy both of them.
860841484cdSPeter Wemm 		 */
8619d08e419SPeter Wemm 		val_flags = sb.f_flags;
8629d08e419SPeter Wemm 		val_type = sb.f_type;
8639b50d902SRodney W. Grimes 	}
864ea92232aSPoul-Henning Kamp 	switch (plan->flags & F_MTMASK) {
8659b50d902SRodney W. Grimes 	case F_MTFLAG:
866ea92232aSPoul-Henning Kamp 		return val_flags & plan->mt_data;
8679b50d902SRodney W. Grimes 	case F_MTTYPE:
868ea92232aSPoul-Henning Kamp 		return val_type == plan->mt_data;
8699b50d902SRodney W. Grimes 	default:
8709b50d902SRodney W. Grimes 		abort();
8719b50d902SRodney W. Grimes 	}
8729b50d902SRodney W. Grimes }
8739b50d902SRodney W. Grimes 
8749b50d902SRodney W. Grimes PLAN *
875ef646f18SMark Murray c_fstype(OPTION *option, char ***argvp)
8769b50d902SRodney W. Grimes {
877ea92232aSPoul-Henning Kamp 	char *fsname;
878e98080b1SDavid Malone 	PLAN *new;
8795965373eSMaxime Henrion 	struct xvfsconf vfc;
8809b50d902SRodney W. Grimes 
881ea92232aSPoul-Henning Kamp 	fsname = nextarg(option, argvp);
8829b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_NOSTAT;
8839b50d902SRodney W. Grimes 
884ea92232aSPoul-Henning Kamp 	new = palloc(option);
885841484cdSPeter Wemm 
886841484cdSPeter Wemm 	/*
887841484cdSPeter Wemm 	 * Check first for a filesystem name.
888841484cdSPeter Wemm 	 */
889ea92232aSPoul-Henning Kamp 	if (getvfsbyname(fsname, &vfc) == 0) {
890ea92232aSPoul-Henning Kamp 		new->flags |= F_MTTYPE;
891841484cdSPeter Wemm 		new->mt_data = vfc.vfc_typenum;
892ea92232aSPoul-Henning Kamp 		return new;
893841484cdSPeter Wemm 	}
894841484cdSPeter Wemm 
895ea92232aSPoul-Henning Kamp 	switch (*fsname) {
8969b50d902SRodney W. Grimes 	case 'l':
897ea92232aSPoul-Henning Kamp 		if (!strcmp(fsname, "local")) {
898ea92232aSPoul-Henning Kamp 			new->flags |= F_MTFLAG;
8999b50d902SRodney W. Grimes 			new->mt_data = MNT_LOCAL;
900ea92232aSPoul-Henning Kamp 			return new;
9019b50d902SRodney W. Grimes 		}
9029b50d902SRodney W. Grimes 		break;
9039b50d902SRodney W. Grimes 	case 'r':
904ea92232aSPoul-Henning Kamp 		if (!strcmp(fsname, "rdonly")) {
905ea92232aSPoul-Henning Kamp 			new->flags |= F_MTFLAG;
9069b50d902SRodney W. Grimes 			new->mt_data = MNT_RDONLY;
907ea92232aSPoul-Henning Kamp 			return new;
9089b50d902SRodney W. Grimes 		}
9099b50d902SRodney W. Grimes 		break;
9109b50d902SRodney W. Grimes 	}
911ea92232aSPoul-Henning Kamp 
9121e2f8412SEivind Eklund 	/*
9131e2f8412SEivind Eklund 	 * We need to make filesystem checks for filesystems
9141e2f8412SEivind Eklund 	 * that exists but aren't in the kernel work.
9151e2f8412SEivind Eklund 	 */
916ea92232aSPoul-Henning Kamp 	fprintf(stderr, "Warning: Unknown filesystem type %s\n", fsname);
917ea92232aSPoul-Henning Kamp 	new->flags |= F_MTUNKNOWN;
918ea92232aSPoul-Henning Kamp 	return new;
9199b50d902SRodney W. Grimes }
9209b50d902SRodney W. Grimes 
9219b50d902SRodney W. Grimes /*
9229b50d902SRodney W. Grimes  * -group gname functions --
9239b50d902SRodney W. Grimes  *
9249b50d902SRodney W. Grimes  *	True if the file belongs to the group gname.  If gname is numeric and
9259b50d902SRodney W. Grimes  *	an equivalent of the getgrnam() function does not return a valid group
9269b50d902SRodney W. Grimes  *	name, gname is taken as a group ID.
9279b50d902SRodney W. Grimes  */
9289b50d902SRodney W. Grimes int
929ef646f18SMark Murray f_group(PLAN *plan, FTSENT *entry)
9309b50d902SRodney W. Grimes {
931ea92232aSPoul-Henning Kamp 	return entry->fts_statp->st_gid == plan->g_data;
9329b50d902SRodney W. Grimes }
9339b50d902SRodney W. Grimes 
9349b50d902SRodney W. Grimes PLAN *
935ef646f18SMark Murray c_group(OPTION *option, char ***argvp)
9369b50d902SRodney W. Grimes {
937ea92232aSPoul-Henning Kamp 	char *gname;
9389b50d902SRodney W. Grimes 	PLAN *new;
9399b50d902SRodney W. Grimes 	struct group *g;
9409b50d902SRodney W. Grimes 	gid_t gid;
9419b50d902SRodney W. Grimes 
942ea92232aSPoul-Henning Kamp 	gname = nextarg(option, argvp);
9439b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_NOSTAT;
9449b50d902SRodney W. Grimes 
9459b50d902SRodney W. Grimes 	g = getgrnam(gname);
9469b50d902SRodney W. Grimes 	if (g == NULL) {
9479b50d902SRodney W. Grimes 		gid = atoi(gname);
9489b50d902SRodney W. Grimes 		if (gid == 0 && gname[0] != '0')
949ea92232aSPoul-Henning Kamp 			errx(1, "%s: %s: no such group", option->name, gname);
9509b50d902SRodney W. Grimes 	} else
9519b50d902SRodney W. Grimes 		gid = g->gr_gid;
9529b50d902SRodney W. Grimes 
953ea92232aSPoul-Henning Kamp 	new = palloc(option);
9549b50d902SRodney W. Grimes 	new->g_data = gid;
955ea92232aSPoul-Henning Kamp 	return new;
9569b50d902SRodney W. Grimes }
9579b50d902SRodney W. Grimes 
9589b50d902SRodney W. Grimes /*
9599b50d902SRodney W. Grimes  * -inum n functions --
9609b50d902SRodney W. Grimes  *
9619b50d902SRodney W. Grimes  *	True if the file has inode # n.
9629b50d902SRodney W. Grimes  */
9639b50d902SRodney W. Grimes int
964ef646f18SMark Murray f_inum(PLAN *plan, FTSENT *entry)
9659b50d902SRodney W. Grimes {
9669b50d902SRodney W. Grimes 	COMPARE(entry->fts_statp->st_ino, plan->i_data);
9679b50d902SRodney W. Grimes }
9689b50d902SRodney W. Grimes 
9699b50d902SRodney W. Grimes PLAN *
970ef646f18SMark Murray c_inum(OPTION *option, char ***argvp)
9719b50d902SRodney W. Grimes {
972ea92232aSPoul-Henning Kamp 	char *inum_str;
9739b50d902SRodney W. Grimes 	PLAN *new;
9749b50d902SRodney W. Grimes 
975ea92232aSPoul-Henning Kamp 	inum_str = nextarg(option, argvp);
9769b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_NOSTAT;
9779b50d902SRodney W. Grimes 
978ea92232aSPoul-Henning Kamp 	new = palloc(option);
979ea92232aSPoul-Henning Kamp 	new->i_data = find_parsenum(new, option->name, inum_str, NULL);
980ea92232aSPoul-Henning Kamp 	return new;
9819b50d902SRodney W. Grimes }
9829b50d902SRodney W. Grimes 
9839b50d902SRodney W. Grimes /*
9849b50d902SRodney W. Grimes  * -links n functions --
9859b50d902SRodney W. Grimes  *
9869b50d902SRodney W. Grimes  *	True if the file has n links.
9879b50d902SRodney W. Grimes  */
9889b50d902SRodney W. Grimes int
989ef646f18SMark Murray f_links(PLAN *plan, FTSENT *entry)
9909b50d902SRodney W. Grimes {
9919b50d902SRodney W. Grimes 	COMPARE(entry->fts_statp->st_nlink, plan->l_data);
9929b50d902SRodney W. Grimes }
9939b50d902SRodney W. Grimes 
9949b50d902SRodney W. Grimes PLAN *
995ef646f18SMark Murray c_links(OPTION *option, char ***argvp)
9969b50d902SRodney W. Grimes {
997ea92232aSPoul-Henning Kamp 	char *nlinks;
9989b50d902SRodney W. Grimes 	PLAN *new;
9999b50d902SRodney W. Grimes 
1000ea92232aSPoul-Henning Kamp 	nlinks = nextarg(option, argvp);
10019b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_NOSTAT;
10029b50d902SRodney W. Grimes 
1003ea92232aSPoul-Henning Kamp 	new = palloc(option);
1004ea92232aSPoul-Henning Kamp 	new->l_data = (nlink_t)find_parsenum(new, option->name, nlinks, NULL);
1005ea92232aSPoul-Henning Kamp 	return new;
10069b50d902SRodney W. Grimes }
10079b50d902SRodney W. Grimes 
10089b50d902SRodney W. Grimes /*
10099b50d902SRodney W. Grimes  * -ls functions --
10109b50d902SRodney W. Grimes  *
10119b50d902SRodney W. Grimes  *	Always true - prints the current entry to stdout in "ls" format.
10129b50d902SRodney W. Grimes  */
10139b50d902SRodney W. Grimes int
1014ef646f18SMark Murray f_ls(PLAN *plan __unused, FTSENT *entry)
10159b50d902SRodney W. Grimes {
10169b50d902SRodney W. Grimes 	printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
1017ea92232aSPoul-Henning Kamp 	return 1;
10189b50d902SRodney W. Grimes }
10199b50d902SRodney W. Grimes 
10209b50d902SRodney W. Grimes PLAN *
1021ef646f18SMark Murray c_ls(OPTION *option, char ***argvp __unused)
10229b50d902SRodney W. Grimes {
10239b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_NOSTAT;
10249b50d902SRodney W. Grimes 	isoutput = 1;
10259b50d902SRodney W. Grimes 
1026ea92232aSPoul-Henning Kamp 	return palloc(option);
10279b50d902SRodney W. Grimes }
10289b50d902SRodney W. Grimes 
10299b50d902SRodney W. Grimes /*
10309b50d902SRodney W. Grimes  * -name functions --
10319b50d902SRodney W. Grimes  *
10329b50d902SRodney W. Grimes  *	True if the basename of the filename being examined
10339b50d902SRodney W. Grimes  *	matches pattern using Pattern Matching Notation S3.14
10349b50d902SRodney W. Grimes  */
10359b50d902SRodney W. Grimes int
1036ef646f18SMark Murray f_name(PLAN *plan, FTSENT *entry)
10379b50d902SRodney W. Grimes {
1038ea92232aSPoul-Henning Kamp 	return !fnmatch(plan->c_data, entry->fts_name,
1039ea92232aSPoul-Henning Kamp 	    plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
10409b50d902SRodney W. Grimes }
10419b50d902SRodney W. Grimes 
10429b50d902SRodney W. Grimes PLAN *
1043ef646f18SMark Murray c_name(OPTION *option, char ***argvp)
10449b50d902SRodney W. Grimes {
1045ea92232aSPoul-Henning Kamp 	char *pattern;
10469b50d902SRodney W. Grimes 	PLAN *new;
10479b50d902SRodney W. Grimes 
1048ea92232aSPoul-Henning Kamp 	pattern = nextarg(option, argvp);
1049ea92232aSPoul-Henning Kamp 	new = palloc(option);
10509b50d902SRodney W. Grimes 	new->c_data = pattern;
1051ea92232aSPoul-Henning Kamp 	return new;
10529b50d902SRodney W. Grimes }
10539b50d902SRodney W. Grimes 
10547c1d4b3aSAkinori MUSHA /*
1055ea92232aSPoul-Henning Kamp  * -newer file functions --
10567c1d4b3aSAkinori MUSHA  *
1057ea92232aSPoul-Henning Kamp  *	True if the current file has been modified more recently
1058ea92232aSPoul-Henning Kamp  *	then the modification time of the file named by the pathname
1059ea92232aSPoul-Henning Kamp  *	file.
10607c1d4b3aSAkinori MUSHA  */
10617c1d4b3aSAkinori MUSHA int
1062ef646f18SMark Murray f_newer(PLAN *plan, FTSENT *entry)
10637c1d4b3aSAkinori MUSHA {
1064ea92232aSPoul-Henning Kamp 	if (plan->flags & F_TIME_C)
1065ea92232aSPoul-Henning Kamp 		return entry->fts_statp->st_ctime > plan->t_data;
1066ea92232aSPoul-Henning Kamp 	else if (plan->flags & F_TIME_A)
1067ea92232aSPoul-Henning Kamp 		return entry->fts_statp->st_atime > plan->t_data;
1068ea92232aSPoul-Henning Kamp 	else
1069ea92232aSPoul-Henning Kamp 		return entry->fts_statp->st_mtime > plan->t_data;
10707c1d4b3aSAkinori MUSHA }
10717c1d4b3aSAkinori MUSHA 
10727c1d4b3aSAkinori MUSHA PLAN *
1073ef646f18SMark Murray c_newer(OPTION *option, char ***argvp)
10747c1d4b3aSAkinori MUSHA {
1075ea92232aSPoul-Henning Kamp 	char *fn_or_tspec;
10767c1d4b3aSAkinori MUSHA 	PLAN *new;
1077ea92232aSPoul-Henning Kamp 	struct stat sb;
10787c1d4b3aSAkinori MUSHA 
1079ea92232aSPoul-Henning Kamp 	fn_or_tspec = nextarg(option, argvp);
1080ea92232aSPoul-Henning Kamp 	ftsoptions &= ~FTS_NOSTAT;
1081ea92232aSPoul-Henning Kamp 
1082ea92232aSPoul-Henning Kamp 	new = palloc(option);
1083ea92232aSPoul-Henning Kamp 	/* compare against what */
1084ea92232aSPoul-Henning Kamp 	if (option->flags & F_TIME2_T) {
108548d09ba6SMark Murray 		new->t_data = get_date(fn_or_tspec, (struct timeb *) 0);
1086ea92232aSPoul-Henning Kamp 		if (new->t_data == (time_t) -1)
1087ea92232aSPoul-Henning Kamp 			errx(1, "Can't parse date/time: %s", fn_or_tspec);
1088ea92232aSPoul-Henning Kamp 	} else {
1089ea92232aSPoul-Henning Kamp 		if (stat(fn_or_tspec, &sb))
1090ea92232aSPoul-Henning Kamp 			err(1, "%s", fn_or_tspec);
1091ea92232aSPoul-Henning Kamp 		if (option->flags & F_TIME2_C)
1092ea92232aSPoul-Henning Kamp 			new->t_data = sb.st_ctime;
1093ea92232aSPoul-Henning Kamp 		else if (option->flags & F_TIME2_A)
1094ea92232aSPoul-Henning Kamp 			new->t_data = sb.st_atime;
1095ea92232aSPoul-Henning Kamp 		else
1096ea92232aSPoul-Henning Kamp 			new->t_data = sb.st_mtime;
1097ea92232aSPoul-Henning Kamp 	}
1098ea92232aSPoul-Henning Kamp 	return new;
10997c1d4b3aSAkinori MUSHA }
11007c1d4b3aSAkinori MUSHA 
1101ea92232aSPoul-Henning Kamp /*
1102ea92232aSPoul-Henning Kamp  * -nogroup functions --
1103ea92232aSPoul-Henning Kamp  *
1104ea92232aSPoul-Henning Kamp  *	True if file belongs to a user ID for which the equivalent
1105ea92232aSPoul-Henning Kamp  *	of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
1106ea92232aSPoul-Henning Kamp  */
1107ea92232aSPoul-Henning Kamp int
1108ef646f18SMark Murray f_nogroup(PLAN *plan __unused, FTSENT *entry)
1109ea92232aSPoul-Henning Kamp {
1110ea92232aSPoul-Henning Kamp 	return group_from_gid(entry->fts_statp->st_gid, 1) == NULL;
1111ea92232aSPoul-Henning Kamp }
1112ea92232aSPoul-Henning Kamp 
1113ea92232aSPoul-Henning Kamp PLAN *
1114ef646f18SMark Murray c_nogroup(OPTION *option, char ***argvp __unused)
1115ea92232aSPoul-Henning Kamp {
1116ea92232aSPoul-Henning Kamp 	ftsoptions &= ~FTS_NOSTAT;
1117ea92232aSPoul-Henning Kamp 
1118ea92232aSPoul-Henning Kamp 	return palloc(option);
1119ea92232aSPoul-Henning Kamp }
1120ea92232aSPoul-Henning Kamp 
1121ea92232aSPoul-Henning Kamp /*
1122ea92232aSPoul-Henning Kamp  * -nouser functions --
1123ea92232aSPoul-Henning Kamp  *
1124ea92232aSPoul-Henning Kamp  *	True if file belongs to a user ID for which the equivalent
1125ea92232aSPoul-Henning Kamp  *	of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
1126ea92232aSPoul-Henning Kamp  */
1127ea92232aSPoul-Henning Kamp int
1128ef646f18SMark Murray f_nouser(PLAN *plan __unused, FTSENT *entry)
1129ea92232aSPoul-Henning Kamp {
1130ea92232aSPoul-Henning Kamp 	return user_from_uid(entry->fts_statp->st_uid, 1) == NULL;
1131ea92232aSPoul-Henning Kamp }
1132ea92232aSPoul-Henning Kamp 
1133ea92232aSPoul-Henning Kamp PLAN *
1134ef646f18SMark Murray c_nouser(OPTION *option, char ***argvp __unused)
1135ea92232aSPoul-Henning Kamp {
1136ea92232aSPoul-Henning Kamp 	ftsoptions &= ~FTS_NOSTAT;
1137ea92232aSPoul-Henning Kamp 
1138ea92232aSPoul-Henning Kamp 	return palloc(option);
1139ea92232aSPoul-Henning Kamp }
1140ea92232aSPoul-Henning Kamp 
1141ea92232aSPoul-Henning Kamp /*
1142ea92232aSPoul-Henning Kamp  * -path functions --
1143ea92232aSPoul-Henning Kamp  *
1144ea92232aSPoul-Henning Kamp  *	True if the path of the filename being examined
1145ea92232aSPoul-Henning Kamp  *	matches pattern using Pattern Matching Notation S3.14
1146ea92232aSPoul-Henning Kamp  */
1147ea92232aSPoul-Henning Kamp int
1148ef646f18SMark Murray f_path(PLAN *plan, FTSENT *entry)
1149ea92232aSPoul-Henning Kamp {
1150ea92232aSPoul-Henning Kamp 	return !fnmatch(plan->c_data, entry->fts_path,
1151ea92232aSPoul-Henning Kamp 	    plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
1152ea92232aSPoul-Henning Kamp }
1153ea92232aSPoul-Henning Kamp 
1154ea92232aSPoul-Henning Kamp /* c_path is the same as c_name */
1155ea92232aSPoul-Henning Kamp 
1156ea92232aSPoul-Henning Kamp /*
1157ea92232aSPoul-Henning Kamp  * -perm functions --
1158ea92232aSPoul-Henning Kamp  *
1159ea92232aSPoul-Henning Kamp  *	The mode argument is used to represent file mode bits.  If it starts
1160ea92232aSPoul-Henning Kamp  *	with a leading digit, it's treated as an octal mode, otherwise as a
1161ea92232aSPoul-Henning Kamp  *	symbolic mode.
1162ea92232aSPoul-Henning Kamp  */
1163ea92232aSPoul-Henning Kamp int
1164ef646f18SMark Murray f_perm(PLAN *plan, FTSENT *entry)
1165ea92232aSPoul-Henning Kamp {
1166ea92232aSPoul-Henning Kamp 	mode_t mode;
1167ea92232aSPoul-Henning Kamp 
1168ea92232aSPoul-Henning Kamp 	mode = entry->fts_statp->st_mode &
1169ea92232aSPoul-Henning Kamp 	    (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
1170ea92232aSPoul-Henning Kamp 	if (plan->flags & F_ATLEAST)
1171ea92232aSPoul-Henning Kamp 		return (plan->m_data | mode) == mode;
1172c0ff9709SRuslan Ermilov 	else if (plan->flags & F_ANY)
1173c0ff9709SRuslan Ermilov 		return (mode & plan->m_data);
1174ea92232aSPoul-Henning Kamp 	else
1175ea92232aSPoul-Henning Kamp 		return mode == plan->m_data;
1176ea92232aSPoul-Henning Kamp 	/* NOTREACHED */
1177ea92232aSPoul-Henning Kamp }
1178ea92232aSPoul-Henning Kamp 
1179ea92232aSPoul-Henning Kamp PLAN *
1180ef646f18SMark Murray c_perm(OPTION *option, char ***argvp)
1181ea92232aSPoul-Henning Kamp {
1182ea92232aSPoul-Henning Kamp 	char *perm;
1183ea92232aSPoul-Henning Kamp 	PLAN *new;
1184ea92232aSPoul-Henning Kamp 	mode_t *set;
1185ea92232aSPoul-Henning Kamp 
1186ea92232aSPoul-Henning Kamp 	perm = nextarg(option, argvp);
1187ea92232aSPoul-Henning Kamp 	ftsoptions &= ~FTS_NOSTAT;
1188ea92232aSPoul-Henning Kamp 
1189ea92232aSPoul-Henning Kamp 	new = palloc(option);
1190ea92232aSPoul-Henning Kamp 
1191ea92232aSPoul-Henning Kamp 	if (*perm == '-') {
1192ea92232aSPoul-Henning Kamp 		new->flags |= F_ATLEAST;
1193ea92232aSPoul-Henning Kamp 		++perm;
1194ea92232aSPoul-Henning Kamp 	} else if (*perm == '+') {
1195ea92232aSPoul-Henning Kamp 		new->flags |= F_ANY;
1196ea92232aSPoul-Henning Kamp 		++perm;
1197ea92232aSPoul-Henning Kamp 	}
1198ea92232aSPoul-Henning Kamp 
1199ea92232aSPoul-Henning Kamp 	if ((set = setmode(perm)) == NULL)
1200ea92232aSPoul-Henning Kamp 		errx(1, "%s: %s: illegal mode string", option->name, perm);
1201ea92232aSPoul-Henning Kamp 
1202ea92232aSPoul-Henning Kamp 	new->m_data = getmode(set, 0);
1203ea92232aSPoul-Henning Kamp 	free(set);
1204ea92232aSPoul-Henning Kamp 	return new;
1205ea92232aSPoul-Henning Kamp }
1206ea92232aSPoul-Henning Kamp 
1207ea92232aSPoul-Henning Kamp /*
1208ea92232aSPoul-Henning Kamp  * -print functions --
1209ea92232aSPoul-Henning Kamp  *
12109725a7b9SPhilippe Charnier  *	Always true, causes the current pathname to be written to
1211ea92232aSPoul-Henning Kamp  *	standard output.
1212ea92232aSPoul-Henning Kamp  */
1213ea92232aSPoul-Henning Kamp int
1214ef646f18SMark Murray f_print(PLAN *plan __unused, FTSENT *entry)
1215ea92232aSPoul-Henning Kamp {
1216ea92232aSPoul-Henning Kamp 	(void)puts(entry->fts_path);
1217ea92232aSPoul-Henning Kamp 	return 1;
1218ea92232aSPoul-Henning Kamp }
1219ea92232aSPoul-Henning Kamp 
1220ea92232aSPoul-Henning Kamp PLAN *
1221ef646f18SMark Murray c_print(OPTION *option, char ***argvp __unused)
1222ea92232aSPoul-Henning Kamp {
1223ea92232aSPoul-Henning Kamp 	isoutput = 1;
1224ea92232aSPoul-Henning Kamp 
1225ea92232aSPoul-Henning Kamp 	return palloc(option);
1226ea92232aSPoul-Henning Kamp }
1227ea92232aSPoul-Henning Kamp 
1228ea92232aSPoul-Henning Kamp /*
1229ea92232aSPoul-Henning Kamp  * -print0 functions --
1230ea92232aSPoul-Henning Kamp  *
12319725a7b9SPhilippe Charnier  *	Always true, causes the current pathname to be written to
1232ea92232aSPoul-Henning Kamp  *	standard output followed by a NUL character
1233ea92232aSPoul-Henning Kamp  */
1234ea92232aSPoul-Henning Kamp int
1235ef646f18SMark Murray f_print0(PLAN *plan __unused, FTSENT *entry)
1236ea92232aSPoul-Henning Kamp {
1237ea92232aSPoul-Henning Kamp 	fputs(entry->fts_path, stdout);
1238ea92232aSPoul-Henning Kamp 	fputc('\0', stdout);
1239ea92232aSPoul-Henning Kamp 	return 1;
1240ea92232aSPoul-Henning Kamp }
1241ea92232aSPoul-Henning Kamp 
1242ea92232aSPoul-Henning Kamp /* c_print0 is the same as c_print */
1243ea92232aSPoul-Henning Kamp 
1244ea92232aSPoul-Henning Kamp /*
1245ea92232aSPoul-Henning Kamp  * -prune functions --
1246ea92232aSPoul-Henning Kamp  *
1247ea92232aSPoul-Henning Kamp  *	Prune a portion of the hierarchy.
1248ea92232aSPoul-Henning Kamp  */
1249ea92232aSPoul-Henning Kamp int
1250ef646f18SMark Murray f_prune(PLAN *plan __unused, FTSENT *entry)
1251ea92232aSPoul-Henning Kamp {
1252ea92232aSPoul-Henning Kamp 	if (fts_set(tree, entry, FTS_SKIP))
1253ea92232aSPoul-Henning Kamp 		err(1, "%s", entry->fts_path);
1254ea92232aSPoul-Henning Kamp 	return 1;
1255ea92232aSPoul-Henning Kamp }
1256ea92232aSPoul-Henning Kamp 
1257ea92232aSPoul-Henning Kamp /* c_prune == c_simple */
12587c1d4b3aSAkinori MUSHA 
12597c1d4b3aSAkinori MUSHA /*
12607c1d4b3aSAkinori MUSHA  * -regex functions --
12617c1d4b3aSAkinori MUSHA  *
12627c1d4b3aSAkinori MUSHA  *	True if the whole path of the file matches pattern using
12637c1d4b3aSAkinori MUSHA  *	regular expression.
12647c1d4b3aSAkinori MUSHA  */
12657c1d4b3aSAkinori MUSHA int
1266ef646f18SMark Murray f_regex(PLAN *plan, FTSENT *entry)
12677c1d4b3aSAkinori MUSHA {
12687c1d4b3aSAkinori MUSHA 	char *str;
126947bca8b0SJuli Mallett 	int len;
12707c1d4b3aSAkinori MUSHA 	regex_t *pre;
12717c1d4b3aSAkinori MUSHA 	regmatch_t pmatch;
12727c1d4b3aSAkinori MUSHA 	int errcode;
12737c1d4b3aSAkinori MUSHA 	char errbuf[LINE_MAX];
12747c1d4b3aSAkinori MUSHA 	int matched;
12757c1d4b3aSAkinori MUSHA 
12767c1d4b3aSAkinori MUSHA 	pre = plan->re_data;
12777c1d4b3aSAkinori MUSHA 	str = entry->fts_path;
12787c1d4b3aSAkinori MUSHA 	len = strlen(str);
12797c1d4b3aSAkinori MUSHA 	matched = 0;
12807c1d4b3aSAkinori MUSHA 
12817c1d4b3aSAkinori MUSHA 	pmatch.rm_so = 0;
12827c1d4b3aSAkinori MUSHA 	pmatch.rm_eo = len;
12837c1d4b3aSAkinori MUSHA 
12847c1d4b3aSAkinori MUSHA 	errcode = regexec(pre, str, 1, &pmatch, REG_STARTEND);
12857c1d4b3aSAkinori MUSHA 
12867c1d4b3aSAkinori MUSHA 	if (errcode != 0 && errcode != REG_NOMATCH) {
12877c1d4b3aSAkinori MUSHA 		regerror(errcode, pre, errbuf, sizeof errbuf);
12887c1d4b3aSAkinori MUSHA 		errx(1, "%s: %s",
1289ea92232aSPoul-Henning Kamp 		     plan->flags & F_IGNCASE ? "-iregex" : "-regex", errbuf);
12907c1d4b3aSAkinori MUSHA 	}
12917c1d4b3aSAkinori MUSHA 
12927c1d4b3aSAkinori MUSHA 	if (errcode == 0 && pmatch.rm_so == 0 && pmatch.rm_eo == len)
12937c1d4b3aSAkinori MUSHA 		matched = 1;
12947c1d4b3aSAkinori MUSHA 
1295ea92232aSPoul-Henning Kamp 	return matched;
12967c1d4b3aSAkinori MUSHA }
12977c1d4b3aSAkinori MUSHA 
12987c1d4b3aSAkinori MUSHA PLAN *
1299ef646f18SMark Murray c_regex(OPTION *option, char ***argvp)
13007c1d4b3aSAkinori MUSHA {
13017c1d4b3aSAkinori MUSHA 	PLAN *new;
1302ea92232aSPoul-Henning Kamp 	char *pattern;
13037c1d4b3aSAkinori MUSHA 	regex_t *pre;
13047c1d4b3aSAkinori MUSHA 	int errcode;
13057c1d4b3aSAkinori MUSHA 	char errbuf[LINE_MAX];
13067c1d4b3aSAkinori MUSHA 
13077c1d4b3aSAkinori MUSHA 	if ((pre = malloc(sizeof(regex_t))) == NULL)
13087c1d4b3aSAkinori MUSHA 		err(1, NULL);
13097c1d4b3aSAkinori MUSHA 
1310ea92232aSPoul-Henning Kamp 	pattern = nextarg(option, argvp);
1311ea92232aSPoul-Henning Kamp 
1312ea92232aSPoul-Henning Kamp 	if ((errcode = regcomp(pre, pattern,
1313ea92232aSPoul-Henning Kamp 	    regexp_flags | (option->flags & F_IGNCASE ? REG_ICASE : 0))) != 0) {
13147c1d4b3aSAkinori MUSHA 		regerror(errcode, pre, errbuf, sizeof errbuf);
13157c1d4b3aSAkinori MUSHA 		errx(1, "%s: %s: %s",
1316ea92232aSPoul-Henning Kamp 		     option->flags & F_IGNCASE ? "-iregex" : "-regex",
1317ea92232aSPoul-Henning Kamp 		     pattern, errbuf);
13187c1d4b3aSAkinori MUSHA 	}
13197c1d4b3aSAkinori MUSHA 
1320ea92232aSPoul-Henning Kamp 	new = palloc(option);
13217c1d4b3aSAkinori MUSHA 	new->re_data = pre;
13227c1d4b3aSAkinori MUSHA 
1323567664c4SOllivier Robert 	return new;
1324567664c4SOllivier Robert }
1325567664c4SOllivier Robert 
1326ea92232aSPoul-Henning Kamp /* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or */
13279b50d902SRodney W. Grimes 
13289b50d902SRodney W. Grimes PLAN *
1329ef646f18SMark Murray c_simple(OPTION *option, char ***argvp __unused)
13309b50d902SRodney W. Grimes {
1331ea92232aSPoul-Henning Kamp 	return palloc(option);
13329b50d902SRodney W. Grimes }
13339b50d902SRodney W. Grimes 
13349b50d902SRodney W. Grimes /*
13359b50d902SRodney W. Grimes  * -size n[c] functions --
13369b50d902SRodney W. Grimes  *
13379b50d902SRodney W. Grimes  *	True if the file size in bytes, divided by an implementation defined
13389b50d902SRodney W. Grimes  *	value and rounded up to the next integer, is n.  If n is followed by
13399b50d902SRodney W. Grimes  *	a c, the size is in bytes.
13409b50d902SRodney W. Grimes  */
13419b50d902SRodney W. Grimes #define	FIND_SIZE	512
13429b50d902SRodney W. Grimes static int divsize = 1;
13439b50d902SRodney W. Grimes 
13449b50d902SRodney W. Grimes int
1345ef646f18SMark Murray f_size(PLAN *plan, FTSENT *entry)
13469b50d902SRodney W. Grimes {
13479b50d902SRodney W. Grimes 	off_t size;
13489b50d902SRodney W. Grimes 
13499b50d902SRodney W. Grimes 	size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
13509b50d902SRodney W. Grimes 	    FIND_SIZE : entry->fts_statp->st_size;
13519b50d902SRodney W. Grimes 	COMPARE(size, plan->o_data);
13529b50d902SRodney W. Grimes }
13539b50d902SRodney W. Grimes 
13549b50d902SRodney W. Grimes PLAN *
1355ef646f18SMark Murray c_size(OPTION *option, char ***argvp)
13569b50d902SRodney W. Grimes {
1357ea92232aSPoul-Henning Kamp 	char *size_str;
13589b50d902SRodney W. Grimes 	PLAN *new;
13599b50d902SRodney W. Grimes 	char endch;
13609b50d902SRodney W. Grimes 
1361ea92232aSPoul-Henning Kamp 	size_str = nextarg(option, argvp);
13629b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_NOSTAT;
13639b50d902SRodney W. Grimes 
1364ea92232aSPoul-Henning Kamp 	new = palloc(option);
13659b50d902SRodney W. Grimes 	endch = 'c';
1366ea92232aSPoul-Henning Kamp 	new->o_data = find_parsenum(new, option->name, size_str, &endch);
13679b50d902SRodney W. Grimes 	if (endch == 'c')
13689b50d902SRodney W. Grimes 		divsize = 0;
1369ea92232aSPoul-Henning Kamp 	return new;
13709b50d902SRodney W. Grimes }
13719b50d902SRodney W. Grimes 
13729b50d902SRodney W. Grimes /*
13739b50d902SRodney W. Grimes  * -type c functions --
13749b50d902SRodney W. Grimes  *
1375841484cdSPeter Wemm  *	True if the type of the file is c, where c is b, c, d, p, f or w
1376841484cdSPeter Wemm  *	for block special file, character special file, directory, FIFO,
1377841484cdSPeter Wemm  *	regular file or whiteout respectively.
13789b50d902SRodney W. Grimes  */
13799b50d902SRodney W. Grimes int
1380ef646f18SMark Murray f_type(PLAN *plan, FTSENT *entry)
13819b50d902SRodney W. Grimes {
1382ea92232aSPoul-Henning Kamp 	return (entry->fts_statp->st_mode & S_IFMT) == plan->m_data;
13839b50d902SRodney W. Grimes }
13849b50d902SRodney W. Grimes 
13859b50d902SRodney W. Grimes PLAN *
1386ef646f18SMark Murray c_type(OPTION *option, char ***argvp)
13879b50d902SRodney W. Grimes {
1388ea92232aSPoul-Henning Kamp 	char *typestring;
13899b50d902SRodney W. Grimes 	PLAN *new;
13909b50d902SRodney W. Grimes 	mode_t  mask;
13919b50d902SRodney W. Grimes 
1392ea92232aSPoul-Henning Kamp 	typestring = nextarg(option, argvp);
13939b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_NOSTAT;
13949b50d902SRodney W. Grimes 
13959b50d902SRodney W. Grimes 	switch (typestring[0]) {
13969b50d902SRodney W. Grimes 	case 'b':
13979b50d902SRodney W. Grimes 		mask = S_IFBLK;
13989b50d902SRodney W. Grimes 		break;
13999b50d902SRodney W. Grimes 	case 'c':
14009b50d902SRodney W. Grimes 		mask = S_IFCHR;
14019b50d902SRodney W. Grimes 		break;
14029b50d902SRodney W. Grimes 	case 'd':
14039b50d902SRodney W. Grimes 		mask = S_IFDIR;
14049b50d902SRodney W. Grimes 		break;
14059b50d902SRodney W. Grimes 	case 'f':
14069b50d902SRodney W. Grimes 		mask = S_IFREG;
14079b50d902SRodney W. Grimes 		break;
14089b50d902SRodney W. Grimes 	case 'l':
14099b50d902SRodney W. Grimes 		mask = S_IFLNK;
14109b50d902SRodney W. Grimes 		break;
14119b50d902SRodney W. Grimes 	case 'p':
14129b50d902SRodney W. Grimes 		mask = S_IFIFO;
14139b50d902SRodney W. Grimes 		break;
14149b50d902SRodney W. Grimes 	case 's':
14159b50d902SRodney W. Grimes 		mask = S_IFSOCK;
14169b50d902SRodney W. Grimes 		break;
1417841484cdSPeter Wemm #ifdef FTS_WHITEOUT
1418841484cdSPeter Wemm 	case 'w':
1419841484cdSPeter Wemm 		mask = S_IFWHT;
1420841484cdSPeter Wemm 		ftsoptions |= FTS_WHITEOUT;
1421841484cdSPeter Wemm 		break;
1422841484cdSPeter Wemm #endif /* FTS_WHITEOUT */
14239b50d902SRodney W. Grimes 	default:
1424ea92232aSPoul-Henning Kamp 		errx(1, "%s: %s: unknown type", option->name, typestring);
14259b50d902SRodney W. Grimes 	}
14269b50d902SRodney W. Grimes 
1427ea92232aSPoul-Henning Kamp 	new = palloc(option);
14289b50d902SRodney W. Grimes 	new->m_data = mask;
1429ea92232aSPoul-Henning Kamp 	return new;
1430abacbbbfSPeter Wemm }
1431abacbbbfSPeter Wemm 
1432abacbbbfSPeter Wemm /*
14339b50d902SRodney W. Grimes  * -user uname functions --
14349b50d902SRodney W. Grimes  *
14359b50d902SRodney W. Grimes  *	True if the file belongs to the user uname.  If uname is numeric and
14369b50d902SRodney W. Grimes  *	an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
14379b50d902SRodney W. Grimes  *	return a valid user name, uname is taken as a user ID.
14389b50d902SRodney W. Grimes  */
14399b50d902SRodney W. Grimes int
1440ef646f18SMark Murray f_user(PLAN *plan, FTSENT *entry)
14419b50d902SRodney W. Grimes {
1442ea92232aSPoul-Henning Kamp 	return entry->fts_statp->st_uid == plan->u_data;
14439b50d902SRodney W. Grimes }
14449b50d902SRodney W. Grimes 
14459b50d902SRodney W. Grimes PLAN *
1446ef646f18SMark Murray c_user(OPTION *option, char ***argvp)
14479b50d902SRodney W. Grimes {
1448ea92232aSPoul-Henning Kamp 	char *username;
14499b50d902SRodney W. Grimes 	PLAN *new;
14509b50d902SRodney W. Grimes 	struct passwd *p;
14519b50d902SRodney W. Grimes 	uid_t uid;
14529b50d902SRodney W. Grimes 
1453ea92232aSPoul-Henning Kamp 	username = nextarg(option, argvp);
14549b50d902SRodney W. Grimes 	ftsoptions &= ~FTS_NOSTAT;
14559b50d902SRodney W. Grimes 
14569b50d902SRodney W. Grimes 	p = getpwnam(username);
14579b50d902SRodney W. Grimes 	if (p == NULL) {
14589b50d902SRodney W. Grimes 		uid = atoi(username);
14599b50d902SRodney W. Grimes 		if (uid == 0 && username[0] != '0')
1460ea92232aSPoul-Henning Kamp 			errx(1, "%s: %s: no such user", option->name, username);
14619b50d902SRodney W. Grimes 	} else
14629b50d902SRodney W. Grimes 		uid = p->pw_uid;
14639b50d902SRodney W. Grimes 
1464ea92232aSPoul-Henning Kamp 	new = palloc(option);
14659b50d902SRodney W. Grimes 	new->u_data = uid;
1466ea92232aSPoul-Henning Kamp 	return new;
14679b50d902SRodney W. Grimes }
14689b50d902SRodney W. Grimes 
14699b50d902SRodney W. Grimes /*
14709b50d902SRodney W. Grimes  * -xdev functions --
14719b50d902SRodney W. Grimes  *
14729725a7b9SPhilippe Charnier  *	Always true, causes find not to descend past directories that have a
14739b50d902SRodney W. Grimes  *	different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
14749b50d902SRodney W. Grimes  */
14759b50d902SRodney W. Grimes PLAN *
1476ef646f18SMark Murray c_xdev(OPTION *option, char ***argvp __unused)
14779b50d902SRodney W. Grimes {
14789b50d902SRodney W. Grimes 	ftsoptions |= FTS_XDEV;
14799b50d902SRodney W. Grimes 
1480ea92232aSPoul-Henning Kamp 	return palloc(option);
14819b50d902SRodney W. Grimes }
14829b50d902SRodney W. Grimes 
14839b50d902SRodney W. Grimes /*
14849b50d902SRodney W. Grimes  * ( expression ) functions --
14859b50d902SRodney W. Grimes  *
14869b50d902SRodney W. Grimes  *	True if expression is true.
14879b50d902SRodney W. Grimes  */
14889b50d902SRodney W. Grimes int
1489ef646f18SMark Murray f_expr(PLAN *plan, FTSENT *entry)
14909b50d902SRodney W. Grimes {
1491e98080b1SDavid Malone 	PLAN *p;
1492e98080b1SDavid Malone 	int state = 0;
14939b50d902SRodney W. Grimes 
14949b50d902SRodney W. Grimes 	for (p = plan->p_data[0];
1495ea92232aSPoul-Henning Kamp 	    p && (state = (p->execute)(p, entry)); p = p->next);
1496ea92232aSPoul-Henning Kamp 	return state;
14979b50d902SRodney W. Grimes }
14989b50d902SRodney W. Grimes 
14999b50d902SRodney W. Grimes /*
1500ea92232aSPoul-Henning Kamp  * f_openparen and f_closeparen nodes are temporary place markers.  They are
15019b50d902SRodney W. Grimes  * eliminated during phase 2 of find_formplan() --- the '(' node is converted
1502ea92232aSPoul-Henning Kamp  * to a f_expr node containing the expression and the ')' node is discarded.
1503ea92232aSPoul-Henning Kamp  * The functions themselves are only used as constants.
15049b50d902SRodney W. Grimes  */
1505ea92232aSPoul-Henning Kamp 
1506ea92232aSPoul-Henning Kamp int
1507ef646f18SMark Murray f_openparen(PLAN *plan __unused, FTSENT *entry __unused)
15089b50d902SRodney W. Grimes {
1509ea92232aSPoul-Henning Kamp 	abort();
15109b50d902SRodney W. Grimes }
15119b50d902SRodney W. Grimes 
1512ea92232aSPoul-Henning Kamp int
1513ef646f18SMark Murray f_closeparen(PLAN *plan __unused, FTSENT *entry __unused)
15149b50d902SRodney W. Grimes {
1515ea92232aSPoul-Henning Kamp 	abort();
1516ea92232aSPoul-Henning Kamp }
1517ea92232aSPoul-Henning Kamp 
1518ea92232aSPoul-Henning Kamp /* c_openparen == c_simple */
1519ea92232aSPoul-Henning Kamp /* c_closeparen == c_simple */
1520ea92232aSPoul-Henning Kamp 
1521ea92232aSPoul-Henning Kamp /*
1522ea92232aSPoul-Henning Kamp  * AND operator. Since AND is implicit, no node is allocated.
1523ea92232aSPoul-Henning Kamp  */
1524ea92232aSPoul-Henning Kamp PLAN *
1525ef646f18SMark Murray c_and(OPTION *option __unused, char ***argvp __unused)
1526ea92232aSPoul-Henning Kamp {
1527ea92232aSPoul-Henning Kamp 	return NULL;
15289b50d902SRodney W. Grimes }
15299b50d902SRodney W. Grimes 
15309b50d902SRodney W. Grimes /*
15319b50d902SRodney W. Grimes  * ! expression functions --
15329b50d902SRodney W. Grimes  *
15339b50d902SRodney W. Grimes  *	Negation of a primary; the unary NOT operator.
15349b50d902SRodney W. Grimes  */
15359b50d902SRodney W. Grimes int
1536ef646f18SMark Murray f_not(PLAN *plan, FTSENT *entry)
15379b50d902SRodney W. Grimes {
1538e98080b1SDavid Malone 	PLAN *p;
1539e98080b1SDavid Malone 	int state = 0;
15409b50d902SRodney W. Grimes 
15419b50d902SRodney W. Grimes 	for (p = plan->p_data[0];
1542ea92232aSPoul-Henning Kamp 	    p && (state = (p->execute)(p, entry)); p = p->next);
1543ea92232aSPoul-Henning Kamp 	return !state;
15449b50d902SRodney W. Grimes }
15459b50d902SRodney W. Grimes 
1546ea92232aSPoul-Henning Kamp /* c_not == c_simple */
15479b50d902SRodney W. Grimes 
15489b50d902SRodney W. Grimes /*
15499b50d902SRodney W. Grimes  * expression -o expression functions --
15509b50d902SRodney W. Grimes  *
15519b50d902SRodney W. Grimes  *	Alternation of primaries; the OR operator.  The second expression is
15529b50d902SRodney W. Grimes  * not evaluated if the first expression is true.
15539b50d902SRodney W. Grimes  */
15549b50d902SRodney W. Grimes int
1555ef646f18SMark Murray f_or(PLAN *plan, FTSENT *entry)
15569b50d902SRodney W. Grimes {
1557e98080b1SDavid Malone 	PLAN *p;
1558e98080b1SDavid Malone 	int state = 0;
15599b50d902SRodney W. Grimes 
15609b50d902SRodney W. Grimes 	for (p = plan->p_data[0];
1561ea92232aSPoul-Henning Kamp 	    p && (state = (p->execute)(p, entry)); p = p->next);
15629b50d902SRodney W. Grimes 
15639b50d902SRodney W. Grimes 	if (state)
1564ea92232aSPoul-Henning Kamp 		return 1;
15659b50d902SRodney W. Grimes 
15669b50d902SRodney W. Grimes 	for (p = plan->p_data[1];
1567ea92232aSPoul-Henning Kamp 	    p && (state = (p->execute)(p, entry)); p = p->next);
1568ea92232aSPoul-Henning Kamp 	return state;
15699b50d902SRodney W. Grimes }
15709b50d902SRodney W. Grimes 
1571ea92232aSPoul-Henning Kamp /* c_or == c_simple */
1572