1319e7a6dSDavid van Moolenbroek /* $NetBSD: function.c,v 1.72 2013/05/04 06:29:32 uebayasi Exp $ */
2319e7a6dSDavid van Moolenbroek
3319e7a6dSDavid van Moolenbroek /*-
4319e7a6dSDavid van Moolenbroek * Copyright (c) 1990, 1993
5319e7a6dSDavid van Moolenbroek * The Regents of the University of California. All rights reserved.
6319e7a6dSDavid van Moolenbroek *
7319e7a6dSDavid van Moolenbroek * This code is derived from software contributed to Berkeley by
8319e7a6dSDavid van Moolenbroek * Cimarron D. Taylor of the University of California, Berkeley.
9319e7a6dSDavid van Moolenbroek *
10319e7a6dSDavid van Moolenbroek * Redistribution and use in source and binary forms, with or without
11319e7a6dSDavid van Moolenbroek * modification, are permitted provided that the following conditions
12319e7a6dSDavid van Moolenbroek * are met:
13319e7a6dSDavid van Moolenbroek * 1. Redistributions of source code must retain the above copyright
14319e7a6dSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer.
15319e7a6dSDavid van Moolenbroek * 2. Redistributions in binary form must reproduce the above copyright
16319e7a6dSDavid van Moolenbroek * notice, this list of conditions and the following disclaimer in the
17319e7a6dSDavid van Moolenbroek * documentation and/or other materials provided with the distribution.
18319e7a6dSDavid van Moolenbroek * 3. Neither the name of the University nor the names of its contributors
19319e7a6dSDavid van Moolenbroek * may be used to endorse or promote products derived from this software
20319e7a6dSDavid van Moolenbroek * without specific prior written permission.
21319e7a6dSDavid van Moolenbroek *
22319e7a6dSDavid van Moolenbroek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23319e7a6dSDavid van Moolenbroek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24319e7a6dSDavid van Moolenbroek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25319e7a6dSDavid van Moolenbroek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26319e7a6dSDavid van Moolenbroek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27319e7a6dSDavid van Moolenbroek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28319e7a6dSDavid van Moolenbroek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29319e7a6dSDavid van Moolenbroek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30319e7a6dSDavid van Moolenbroek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31319e7a6dSDavid van Moolenbroek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32319e7a6dSDavid van Moolenbroek * SUCH DAMAGE.
33319e7a6dSDavid van Moolenbroek */
34319e7a6dSDavid van Moolenbroek
35319e7a6dSDavid van Moolenbroek #include <sys/cdefs.h>
36319e7a6dSDavid van Moolenbroek #ifndef lint
37319e7a6dSDavid van Moolenbroek #if 0
38319e7a6dSDavid van Moolenbroek static char sccsid[] = "from: @(#)function.c 8.10 (Berkeley) 5/4/95";
39319e7a6dSDavid van Moolenbroek #else
40319e7a6dSDavid van Moolenbroek __RCSID("$NetBSD: function.c,v 1.72 2013/05/04 06:29:32 uebayasi Exp $");
41319e7a6dSDavid van Moolenbroek #endif
42319e7a6dSDavid van Moolenbroek #endif /* not lint */
43319e7a6dSDavid van Moolenbroek
44319e7a6dSDavid van Moolenbroek #include <sys/param.h>
45319e7a6dSDavid van Moolenbroek #include <sys/stat.h>
46319e7a6dSDavid van Moolenbroek #include <sys/wait.h>
47319e7a6dSDavid van Moolenbroek #include <sys/mount.h>
48319e7a6dSDavid van Moolenbroek
49319e7a6dSDavid van Moolenbroek #include <dirent.h>
50319e7a6dSDavid van Moolenbroek #include <err.h>
51319e7a6dSDavid van Moolenbroek #include <errno.h>
52319e7a6dSDavid van Moolenbroek #include <fnmatch.h>
53319e7a6dSDavid van Moolenbroek #include <fts.h>
54319e7a6dSDavid van Moolenbroek #include <grp.h>
55319e7a6dSDavid van Moolenbroek #include <inttypes.h>
56319e7a6dSDavid van Moolenbroek #include <limits.h>
57319e7a6dSDavid van Moolenbroek #include <pwd.h>
58319e7a6dSDavid van Moolenbroek #include <stdbool.h>
59319e7a6dSDavid van Moolenbroek #include <stdio.h>
60319e7a6dSDavid van Moolenbroek #include <stdlib.h>
61319e7a6dSDavid van Moolenbroek #include <string.h>
62319e7a6dSDavid van Moolenbroek #include <tzfile.h>
63319e7a6dSDavid van Moolenbroek #include <unistd.h>
64319e7a6dSDavid van Moolenbroek #include <util.h>
65319e7a6dSDavid van Moolenbroek
66319e7a6dSDavid van Moolenbroek #include "find.h"
67319e7a6dSDavid van Moolenbroek
68319e7a6dSDavid van Moolenbroek #define COMPARE(a, b) { \
69319e7a6dSDavid van Moolenbroek switch (plan->flags) { \
70319e7a6dSDavid van Moolenbroek case F_EQUAL: \
71319e7a6dSDavid van Moolenbroek return (a == b); \
72319e7a6dSDavid van Moolenbroek case F_LESSTHAN: \
73319e7a6dSDavid van Moolenbroek return (a < b); \
74319e7a6dSDavid van Moolenbroek case F_GREATER: \
75319e7a6dSDavid van Moolenbroek return (a > b); \
76319e7a6dSDavid van Moolenbroek default: \
77319e7a6dSDavid van Moolenbroek abort(); \
78319e7a6dSDavid van Moolenbroek } \
79319e7a6dSDavid van Moolenbroek }
80319e7a6dSDavid van Moolenbroek
81319e7a6dSDavid van Moolenbroek static int64_t find_parsenum(PLAN *, const char *, const char *, char *);
82319e7a6dSDavid van Moolenbroek static void run_f_exec(PLAN *);
83319e7a6dSDavid van Moolenbroek int f_always_true(PLAN *, FTSENT *);
84319e7a6dSDavid van Moolenbroek int f_amin(PLAN *, FTSENT *);
85319e7a6dSDavid van Moolenbroek int f_anewer(PLAN *, FTSENT *);
86319e7a6dSDavid van Moolenbroek int f_atime(PLAN *, FTSENT *);
87319e7a6dSDavid van Moolenbroek int f_cmin(PLAN *, FTSENT *);
88319e7a6dSDavid van Moolenbroek int f_cnewer(PLAN *, FTSENT *);
89319e7a6dSDavid van Moolenbroek int f_ctime(PLAN *, FTSENT *);
90319e7a6dSDavid van Moolenbroek int f_delete(PLAN *, FTSENT *);
91319e7a6dSDavid van Moolenbroek int f_empty(PLAN *, FTSENT *);
92319e7a6dSDavid van Moolenbroek int f_exec(PLAN *, FTSENT *);
93319e7a6dSDavid van Moolenbroek int f_execdir(PLAN *, FTSENT *);
94319e7a6dSDavid van Moolenbroek int f_false(PLAN *, FTSENT *);
95319e7a6dSDavid van Moolenbroek int f_flags(PLAN *, FTSENT *);
96319e7a6dSDavid van Moolenbroek int f_fprint(PLAN *, FTSENT *);
97319e7a6dSDavid van Moolenbroek int f_fstype(PLAN *, FTSENT *);
98319e7a6dSDavid van Moolenbroek int f_group(PLAN *, FTSENT *);
99319e7a6dSDavid van Moolenbroek int f_iname(PLAN *, FTSENT *);
100319e7a6dSDavid van Moolenbroek int f_inum(PLAN *, FTSENT *);
101319e7a6dSDavid van Moolenbroek int f_links(PLAN *, FTSENT *);
102319e7a6dSDavid van Moolenbroek int f_ls(PLAN *, FTSENT *);
103319e7a6dSDavid van Moolenbroek int f_mindepth(PLAN *, FTSENT *);
104319e7a6dSDavid van Moolenbroek int f_maxdepth(PLAN *, FTSENT *);
105319e7a6dSDavid van Moolenbroek int f_mmin(PLAN *, FTSENT *);
106319e7a6dSDavid van Moolenbroek int f_mtime(PLAN *, FTSENT *);
107319e7a6dSDavid van Moolenbroek int f_name(PLAN *, FTSENT *);
108319e7a6dSDavid van Moolenbroek int f_newer(PLAN *, FTSENT *);
109319e7a6dSDavid van Moolenbroek int f_nogroup(PLAN *, FTSENT *);
110319e7a6dSDavid van Moolenbroek int f_nouser(PLAN *, FTSENT *);
111319e7a6dSDavid van Moolenbroek int f_path(PLAN *, FTSENT *);
112319e7a6dSDavid van Moolenbroek int f_perm(PLAN *, FTSENT *);
113319e7a6dSDavid van Moolenbroek int f_print(PLAN *, FTSENT *);
114319e7a6dSDavid van Moolenbroek int f_print0(PLAN *, FTSENT *);
115319e7a6dSDavid van Moolenbroek int f_printx(PLAN *, FTSENT *);
116319e7a6dSDavid van Moolenbroek int f_prune(PLAN *, FTSENT *);
117319e7a6dSDavid van Moolenbroek int f_regex(PLAN *, FTSENT *);
118319e7a6dSDavid van Moolenbroek int f_size(PLAN *, FTSENT *);
119319e7a6dSDavid van Moolenbroek int f_type(PLAN *, FTSENT *);
120319e7a6dSDavid van Moolenbroek int f_user(PLAN *, FTSENT *);
121319e7a6dSDavid van Moolenbroek int f_not(PLAN *, FTSENT *);
122319e7a6dSDavid van Moolenbroek int f_or(PLAN *, FTSENT *);
123319e7a6dSDavid van Moolenbroek static PLAN *c_regex_common(char ***, int, enum ntype, bool);
124319e7a6dSDavid van Moolenbroek static PLAN *palloc(enum ntype, int (*)(PLAN *, FTSENT *));
125319e7a6dSDavid van Moolenbroek
126319e7a6dSDavid van Moolenbroek extern int dotfd;
127319e7a6dSDavid van Moolenbroek extern FTS *tree;
128319e7a6dSDavid van Moolenbroek extern time_t now;
129319e7a6dSDavid van Moolenbroek
130319e7a6dSDavid van Moolenbroek /*
131319e7a6dSDavid van Moolenbroek * find_parsenum --
132319e7a6dSDavid van Moolenbroek * Parse a string of the form [+-]# and return the value.
133319e7a6dSDavid van Moolenbroek */
134319e7a6dSDavid van Moolenbroek static int64_t
find_parsenum(PLAN * plan,const char * option,const char * vp,char * endch)135319e7a6dSDavid van Moolenbroek find_parsenum(PLAN *plan, const char *option, const char *vp, char *endch)
136319e7a6dSDavid van Moolenbroek {
137319e7a6dSDavid van Moolenbroek int64_t value;
138319e7a6dSDavid van Moolenbroek const char *str;
139319e7a6dSDavid van Moolenbroek char *endchar; /* Pointer to character ending conversion. */
140319e7a6dSDavid van Moolenbroek
141319e7a6dSDavid van Moolenbroek /* Determine comparison from leading + or -. */
142319e7a6dSDavid van Moolenbroek str = vp;
143319e7a6dSDavid van Moolenbroek switch (*str) {
144319e7a6dSDavid van Moolenbroek case '+':
145319e7a6dSDavid van Moolenbroek ++str;
146319e7a6dSDavid van Moolenbroek plan->flags = F_GREATER;
147319e7a6dSDavid van Moolenbroek break;
148319e7a6dSDavid van Moolenbroek case '-':
149319e7a6dSDavid van Moolenbroek ++str;
150319e7a6dSDavid van Moolenbroek plan->flags = F_LESSTHAN;
151319e7a6dSDavid van Moolenbroek break;
152319e7a6dSDavid van Moolenbroek default:
153319e7a6dSDavid van Moolenbroek plan->flags = F_EQUAL;
154319e7a6dSDavid van Moolenbroek break;
155319e7a6dSDavid van Moolenbroek }
156319e7a6dSDavid van Moolenbroek
157319e7a6dSDavid van Moolenbroek /*
158319e7a6dSDavid van Moolenbroek * Convert the string with strtol(). Note, if strtol() returns zero
159319e7a6dSDavid van Moolenbroek * and endchar points to the beginning of the string we know we have
160319e7a6dSDavid van Moolenbroek * a syntax error.
161319e7a6dSDavid van Moolenbroek */
162319e7a6dSDavid van Moolenbroek value = strtoq(str, &endchar, 10);
163319e7a6dSDavid van Moolenbroek if (value == 0 && endchar == str)
164319e7a6dSDavid van Moolenbroek errx(1, "%s: %s: illegal numeric value", option, vp);
165319e7a6dSDavid van Moolenbroek if (endchar[0] && (endch == NULL || endchar[0] != *endch))
166319e7a6dSDavid van Moolenbroek errx(1, "%s: %s: illegal trailing character", option, vp);
167319e7a6dSDavid van Moolenbroek if (endch)
168319e7a6dSDavid van Moolenbroek *endch = endchar[0];
169319e7a6dSDavid van Moolenbroek return (value);
170319e7a6dSDavid van Moolenbroek }
171319e7a6dSDavid van Moolenbroek
172319e7a6dSDavid van Moolenbroek /*
173319e7a6dSDavid van Moolenbroek * The value of n for the inode times (atime, ctime, and mtime) is a range,
174319e7a6dSDavid van Moolenbroek * i.e. n matches from (n - 1) to n 24 hour periods. This interacts with
175319e7a6dSDavid van Moolenbroek * -n, such that "-mtime -1" would be less than 0 days, which isn't what the
176319e7a6dSDavid van Moolenbroek * user wanted. Correct so that -1 is "less than 1".
177319e7a6dSDavid van Moolenbroek */
178319e7a6dSDavid van Moolenbroek #define TIME_CORRECT(p, ttype) \
179319e7a6dSDavid van Moolenbroek if ((p)->type == ttype && (p)->flags == F_LESSTHAN) \
180319e7a6dSDavid van Moolenbroek ++((p)->t_data);
181319e7a6dSDavid van Moolenbroek
182319e7a6dSDavid van Moolenbroek /*
183319e7a6dSDavid van Moolenbroek * -amin n functions --
184319e7a6dSDavid van Moolenbroek *
185319e7a6dSDavid van Moolenbroek * True if the difference between the file access time and the
186319e7a6dSDavid van Moolenbroek * current time is n 1 minute periods.
187319e7a6dSDavid van Moolenbroek */
188319e7a6dSDavid van Moolenbroek int
f_amin(PLAN * plan,FTSENT * entry)189319e7a6dSDavid van Moolenbroek f_amin(PLAN *plan, FTSENT *entry)
190319e7a6dSDavid van Moolenbroek {
191319e7a6dSDavid van Moolenbroek COMPARE((now - entry->fts_statp->st_atime +
192319e7a6dSDavid van Moolenbroek SECSPERMIN - 1) / SECSPERMIN, plan->t_data);
193319e7a6dSDavid van Moolenbroek }
194319e7a6dSDavid van Moolenbroek
195319e7a6dSDavid van Moolenbroek PLAN *
c_amin(char *** argvp,int isok)196319e7a6dSDavid van Moolenbroek c_amin(char ***argvp, int isok)
197319e7a6dSDavid van Moolenbroek {
198319e7a6dSDavid van Moolenbroek char *arg = **argvp;
199319e7a6dSDavid van Moolenbroek PLAN *new;
200319e7a6dSDavid van Moolenbroek
201319e7a6dSDavid van Moolenbroek (*argvp)++;
202319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
203319e7a6dSDavid van Moolenbroek
204319e7a6dSDavid van Moolenbroek new = palloc(N_AMIN, f_amin);
205319e7a6dSDavid van Moolenbroek new->t_data = find_parsenum(new, "-amin", arg, NULL);
206319e7a6dSDavid van Moolenbroek TIME_CORRECT(new, N_AMIN);
207319e7a6dSDavid van Moolenbroek return (new);
208319e7a6dSDavid van Moolenbroek }
209319e7a6dSDavid van Moolenbroek
210319e7a6dSDavid van Moolenbroek /*
211319e7a6dSDavid van Moolenbroek * -anewer file functions --
212319e7a6dSDavid van Moolenbroek *
213319e7a6dSDavid van Moolenbroek * True if the current file has been accessed more recently
214319e7a6dSDavid van Moolenbroek * than the access time of the file named by the pathname
215319e7a6dSDavid van Moolenbroek * file.
216319e7a6dSDavid van Moolenbroek */
217319e7a6dSDavid van Moolenbroek int
f_anewer(PLAN * plan,FTSENT * entry)218319e7a6dSDavid van Moolenbroek f_anewer(PLAN *plan, FTSENT *entry)
219319e7a6dSDavid van Moolenbroek {
220319e7a6dSDavid van Moolenbroek
221319e7a6dSDavid van Moolenbroek return timespeccmp(&entry->fts_statp->st_atim, &plan->ts_data, >);
222319e7a6dSDavid van Moolenbroek }
223319e7a6dSDavid van Moolenbroek
224319e7a6dSDavid van Moolenbroek PLAN *
c_anewer(char *** argvp,int isok)225319e7a6dSDavid van Moolenbroek c_anewer(char ***argvp, int isok)
226319e7a6dSDavid van Moolenbroek {
227319e7a6dSDavid van Moolenbroek char *filename = **argvp;
228319e7a6dSDavid van Moolenbroek PLAN *new;
229319e7a6dSDavid van Moolenbroek struct stat sb;
230319e7a6dSDavid van Moolenbroek
231319e7a6dSDavid van Moolenbroek (*argvp)++;
232319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
233319e7a6dSDavid van Moolenbroek
234319e7a6dSDavid van Moolenbroek if (stat(filename, &sb))
235319e7a6dSDavid van Moolenbroek err(1, "%s", filename);
236319e7a6dSDavid van Moolenbroek new = palloc(N_ANEWER, f_anewer);
237319e7a6dSDavid van Moolenbroek new->ts_data = sb.st_atim;
238319e7a6dSDavid van Moolenbroek return (new);
239319e7a6dSDavid van Moolenbroek }
240319e7a6dSDavid van Moolenbroek
241319e7a6dSDavid van Moolenbroek /*
242319e7a6dSDavid van Moolenbroek * -atime n functions --
243319e7a6dSDavid van Moolenbroek *
244319e7a6dSDavid van Moolenbroek * True if the difference between the file access time and the
245319e7a6dSDavid van Moolenbroek * current time is n 24 hour periods.
246319e7a6dSDavid van Moolenbroek */
247319e7a6dSDavid van Moolenbroek int
f_atime(PLAN * plan,FTSENT * entry)248319e7a6dSDavid van Moolenbroek f_atime(PLAN *plan, FTSENT *entry)
249319e7a6dSDavid van Moolenbroek {
250319e7a6dSDavid van Moolenbroek COMPARE((now - entry->fts_statp->st_atime +
251319e7a6dSDavid van Moolenbroek SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
252319e7a6dSDavid van Moolenbroek }
253319e7a6dSDavid van Moolenbroek
254319e7a6dSDavid van Moolenbroek PLAN *
c_atime(char *** argvp,int isok)255319e7a6dSDavid van Moolenbroek c_atime(char ***argvp, int isok)
256319e7a6dSDavid van Moolenbroek {
257319e7a6dSDavid van Moolenbroek char *arg = **argvp;
258319e7a6dSDavid van Moolenbroek PLAN *new;
259319e7a6dSDavid van Moolenbroek
260319e7a6dSDavid van Moolenbroek (*argvp)++;
261319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
262319e7a6dSDavid van Moolenbroek
263319e7a6dSDavid van Moolenbroek new = palloc(N_ATIME, f_atime);
264319e7a6dSDavid van Moolenbroek new->t_data = find_parsenum(new, "-atime", arg, NULL);
265319e7a6dSDavid van Moolenbroek TIME_CORRECT(new, N_ATIME);
266319e7a6dSDavid van Moolenbroek return (new);
267319e7a6dSDavid van Moolenbroek }
268319e7a6dSDavid van Moolenbroek
269319e7a6dSDavid van Moolenbroek /*
270319e7a6dSDavid van Moolenbroek * -cmin n functions --
271319e7a6dSDavid van Moolenbroek *
272319e7a6dSDavid van Moolenbroek * True if the difference between the last change of file
273319e7a6dSDavid van Moolenbroek * status information and the current time is n 24 hour periods.
274319e7a6dSDavid van Moolenbroek */
275319e7a6dSDavid van Moolenbroek int
f_cmin(PLAN * plan,FTSENT * entry)276319e7a6dSDavid van Moolenbroek f_cmin(PLAN *plan, FTSENT *entry)
277319e7a6dSDavid van Moolenbroek {
278319e7a6dSDavid van Moolenbroek COMPARE((now - entry->fts_statp->st_ctime +
279319e7a6dSDavid van Moolenbroek SECSPERMIN - 1) / SECSPERMIN, plan->t_data);
280319e7a6dSDavid van Moolenbroek }
281319e7a6dSDavid van Moolenbroek
282319e7a6dSDavid van Moolenbroek PLAN *
c_cmin(char *** argvp,int isok)283319e7a6dSDavid van Moolenbroek c_cmin(char ***argvp, int isok)
284319e7a6dSDavid van Moolenbroek {
285319e7a6dSDavid van Moolenbroek char *arg = **argvp;
286319e7a6dSDavid van Moolenbroek PLAN *new;
287319e7a6dSDavid van Moolenbroek
288319e7a6dSDavid van Moolenbroek (*argvp)++;
289319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
290319e7a6dSDavid van Moolenbroek
291319e7a6dSDavid van Moolenbroek new = palloc(N_CMIN, f_cmin);
292319e7a6dSDavid van Moolenbroek new->t_data = find_parsenum(new, "-cmin", arg, NULL);
293319e7a6dSDavid van Moolenbroek TIME_CORRECT(new, N_CMIN);
294319e7a6dSDavid van Moolenbroek return (new);
295319e7a6dSDavid van Moolenbroek }
296319e7a6dSDavid van Moolenbroek
297319e7a6dSDavid van Moolenbroek /*
298319e7a6dSDavid van Moolenbroek * -cnewer file functions --
299319e7a6dSDavid van Moolenbroek *
300319e7a6dSDavid van Moolenbroek * True if the current file has been changed more recently
301319e7a6dSDavid van Moolenbroek * than the changed time of the file named by the pathname
302319e7a6dSDavid van Moolenbroek * file.
303319e7a6dSDavid van Moolenbroek */
304319e7a6dSDavid van Moolenbroek int
f_cnewer(PLAN * plan,FTSENT * entry)305319e7a6dSDavid van Moolenbroek f_cnewer(PLAN *plan, FTSENT *entry)
306319e7a6dSDavid van Moolenbroek {
307319e7a6dSDavid van Moolenbroek
308319e7a6dSDavid van Moolenbroek return timespeccmp(&entry->fts_statp->st_ctim, &plan->ts_data, >);
309319e7a6dSDavid van Moolenbroek }
310319e7a6dSDavid van Moolenbroek
311319e7a6dSDavid van Moolenbroek PLAN *
c_cnewer(char *** argvp,int isok)312319e7a6dSDavid van Moolenbroek c_cnewer(char ***argvp, int isok)
313319e7a6dSDavid van Moolenbroek {
314319e7a6dSDavid van Moolenbroek char *filename = **argvp;
315319e7a6dSDavid van Moolenbroek PLAN *new;
316319e7a6dSDavid van Moolenbroek struct stat sb;
317319e7a6dSDavid van Moolenbroek
318319e7a6dSDavid van Moolenbroek (*argvp)++;
319319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
320319e7a6dSDavid van Moolenbroek
321319e7a6dSDavid van Moolenbroek if (stat(filename, &sb))
322319e7a6dSDavid van Moolenbroek err(1, "%s", filename);
323319e7a6dSDavid van Moolenbroek new = palloc(N_CNEWER, f_cnewer);
324319e7a6dSDavid van Moolenbroek new->ts_data = sb.st_ctim;
325319e7a6dSDavid van Moolenbroek return (new);
326319e7a6dSDavid van Moolenbroek }
327319e7a6dSDavid van Moolenbroek
328319e7a6dSDavid van Moolenbroek /*
329319e7a6dSDavid van Moolenbroek * -ctime n functions --
330319e7a6dSDavid van Moolenbroek *
331319e7a6dSDavid van Moolenbroek * True if the difference between the last change of file
332319e7a6dSDavid van Moolenbroek * status information and the current time is n 24 hour periods.
333319e7a6dSDavid van Moolenbroek */
334319e7a6dSDavid van Moolenbroek int
f_ctime(PLAN * plan,FTSENT * entry)335319e7a6dSDavid van Moolenbroek f_ctime(PLAN *plan, FTSENT *entry)
336319e7a6dSDavid van Moolenbroek {
337319e7a6dSDavid van Moolenbroek COMPARE((now - entry->fts_statp->st_ctime +
338319e7a6dSDavid van Moolenbroek SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
339319e7a6dSDavid van Moolenbroek }
340319e7a6dSDavid van Moolenbroek
341319e7a6dSDavid van Moolenbroek PLAN *
c_ctime(char *** argvp,int isok)342319e7a6dSDavid van Moolenbroek c_ctime(char ***argvp, int isok)
343319e7a6dSDavid van Moolenbroek {
344319e7a6dSDavid van Moolenbroek char *arg = **argvp;
345319e7a6dSDavid van Moolenbroek PLAN *new;
346319e7a6dSDavid van Moolenbroek
347319e7a6dSDavid van Moolenbroek (*argvp)++;
348319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
349319e7a6dSDavid van Moolenbroek
350319e7a6dSDavid van Moolenbroek new = palloc(N_CTIME, f_ctime);
351319e7a6dSDavid van Moolenbroek new->t_data = find_parsenum(new, "-ctime", arg, NULL);
352319e7a6dSDavid van Moolenbroek TIME_CORRECT(new, N_CTIME);
353319e7a6dSDavid van Moolenbroek return (new);
354319e7a6dSDavid van Moolenbroek }
355319e7a6dSDavid van Moolenbroek
356319e7a6dSDavid van Moolenbroek /*
357319e7a6dSDavid van Moolenbroek * -delete functions --
358319e7a6dSDavid van Moolenbroek *
359319e7a6dSDavid van Moolenbroek * Always true. Makes its best shot and continues on regardless.
360319e7a6dSDavid van Moolenbroek */
361319e7a6dSDavid van Moolenbroek int
f_delete(PLAN * plan __unused,FTSENT * entry)362319e7a6dSDavid van Moolenbroek f_delete(PLAN *plan __unused, FTSENT *entry)
363319e7a6dSDavid van Moolenbroek {
364319e7a6dSDavid van Moolenbroek /* ignore these from fts */
365319e7a6dSDavid van Moolenbroek if (strcmp(entry->fts_accpath, ".") == 0 ||
366319e7a6dSDavid van Moolenbroek strcmp(entry->fts_accpath, "..") == 0)
367319e7a6dSDavid van Moolenbroek return 1;
368319e7a6dSDavid van Moolenbroek
369319e7a6dSDavid van Moolenbroek /* sanity check */
370319e7a6dSDavid van Moolenbroek if (isdepth == 0 || /* depth off */
371319e7a6dSDavid van Moolenbroek (ftsoptions & FTS_NOSTAT) || /* not stat()ing */
372319e7a6dSDavid van Moolenbroek !(ftsoptions & FTS_PHYSICAL) || /* physical off */
373319e7a6dSDavid van Moolenbroek (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */
374319e7a6dSDavid van Moolenbroek errx(1, "-delete: insecure options got turned on");
375319e7a6dSDavid van Moolenbroek
376319e7a6dSDavid van Moolenbroek /* Potentially unsafe - do not accept relative paths whatsoever */
377319e7a6dSDavid van Moolenbroek if (strchr(entry->fts_accpath, '/') != NULL)
378319e7a6dSDavid van Moolenbroek errx(1, "-delete: %s: relative path potentially not safe",
379319e7a6dSDavid van Moolenbroek entry->fts_accpath);
380319e7a6dSDavid van Moolenbroek
381*0a6a1f1dSLionel Sambuc #if !defined(__minix)
382319e7a6dSDavid van Moolenbroek /* Turn off user immutable bits if running as root */
383319e7a6dSDavid van Moolenbroek if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
384319e7a6dSDavid van Moolenbroek !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
385319e7a6dSDavid van Moolenbroek geteuid() == 0)
386319e7a6dSDavid van Moolenbroek chflags(entry->fts_accpath,
387319e7a6dSDavid van Moolenbroek entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
388*0a6a1f1dSLionel Sambuc #endif /* !defined(__minix) */
389319e7a6dSDavid van Moolenbroek
390319e7a6dSDavid van Moolenbroek /* rmdir directories, unlink everything else */
391319e7a6dSDavid van Moolenbroek if (S_ISDIR(entry->fts_statp->st_mode)) {
392319e7a6dSDavid van Moolenbroek if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
393319e7a6dSDavid van Moolenbroek warn("-delete: rmdir(%s)", entry->fts_path);
394319e7a6dSDavid van Moolenbroek } else {
395319e7a6dSDavid van Moolenbroek if (unlink(entry->fts_accpath) < 0)
396319e7a6dSDavid van Moolenbroek warn("-delete: unlink(%s)", entry->fts_path);
397319e7a6dSDavid van Moolenbroek }
398319e7a6dSDavid van Moolenbroek
399319e7a6dSDavid van Moolenbroek /* "succeed" */
400319e7a6dSDavid van Moolenbroek return 1;
401319e7a6dSDavid van Moolenbroek }
402319e7a6dSDavid van Moolenbroek
403319e7a6dSDavid van Moolenbroek PLAN *
c_delete(char *** argvp __unused,int isok)404319e7a6dSDavid van Moolenbroek c_delete(char ***argvp __unused, int isok)
405319e7a6dSDavid van Moolenbroek {
406319e7a6dSDavid van Moolenbroek
407319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT; /* no optimize */
408319e7a6dSDavid van Moolenbroek ftsoptions |= FTS_PHYSICAL; /* disable -follow */
409319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_LOGICAL; /* disable -follow */
410319e7a6dSDavid van Moolenbroek isoutput = 1; /* possible output */
411319e7a6dSDavid van Moolenbroek isdepth = 1; /* -depth implied */
412319e7a6dSDavid van Moolenbroek
413319e7a6dSDavid van Moolenbroek return palloc(N_DELETE, f_delete);
414319e7a6dSDavid van Moolenbroek }
415319e7a6dSDavid van Moolenbroek
416319e7a6dSDavid van Moolenbroek /*
417319e7a6dSDavid van Moolenbroek * -depth functions --
418319e7a6dSDavid van Moolenbroek *
419319e7a6dSDavid van Moolenbroek * Always true, causes descent of the directory hierarchy to be done
420319e7a6dSDavid van Moolenbroek * so that all entries in a directory are acted on before the directory
421319e7a6dSDavid van Moolenbroek * itself.
422319e7a6dSDavid van Moolenbroek */
423319e7a6dSDavid van Moolenbroek int
f_always_true(PLAN * plan,FTSENT * entry)424319e7a6dSDavid van Moolenbroek f_always_true(PLAN *plan, FTSENT *entry)
425319e7a6dSDavid van Moolenbroek {
426319e7a6dSDavid van Moolenbroek
427319e7a6dSDavid van Moolenbroek return (1);
428319e7a6dSDavid van Moolenbroek }
429319e7a6dSDavid van Moolenbroek
430319e7a6dSDavid van Moolenbroek PLAN *
c_depth(char *** argvp,int isok)431319e7a6dSDavid van Moolenbroek c_depth(char ***argvp, int isok)
432319e7a6dSDavid van Moolenbroek {
433319e7a6dSDavid van Moolenbroek isdepth = 1;
434319e7a6dSDavid van Moolenbroek
435319e7a6dSDavid van Moolenbroek return (palloc(N_DEPTH, f_always_true));
436319e7a6dSDavid van Moolenbroek }
437319e7a6dSDavid van Moolenbroek
438319e7a6dSDavid van Moolenbroek /*
439319e7a6dSDavid van Moolenbroek * -empty functions --
440319e7a6dSDavid van Moolenbroek *
441319e7a6dSDavid van Moolenbroek * True if the file or directory is empty
442319e7a6dSDavid van Moolenbroek */
443319e7a6dSDavid van Moolenbroek int
f_empty(PLAN * plan,FTSENT * entry)444319e7a6dSDavid van Moolenbroek f_empty(PLAN *plan, FTSENT *entry)
445319e7a6dSDavid van Moolenbroek {
446319e7a6dSDavid van Moolenbroek if (S_ISREG(entry->fts_statp->st_mode) &&
447319e7a6dSDavid van Moolenbroek entry->fts_statp->st_size == 0)
448319e7a6dSDavid van Moolenbroek return (1);
449319e7a6dSDavid van Moolenbroek if (S_ISDIR(entry->fts_statp->st_mode)) {
450319e7a6dSDavid van Moolenbroek struct dirent *dp;
451319e7a6dSDavid van Moolenbroek int empty;
452319e7a6dSDavid van Moolenbroek DIR *dir;
453319e7a6dSDavid van Moolenbroek
454319e7a6dSDavid van Moolenbroek empty = 1;
455319e7a6dSDavid van Moolenbroek dir = opendir(entry->fts_accpath);
456319e7a6dSDavid van Moolenbroek if (dir == NULL)
457319e7a6dSDavid van Moolenbroek return (0);
458319e7a6dSDavid van Moolenbroek for (dp = readdir(dir); dp; dp = readdir(dir))
459319e7a6dSDavid van Moolenbroek if (dp->d_name[0] != '.' ||
460319e7a6dSDavid van Moolenbroek (dp->d_name[1] != '\0' &&
461319e7a6dSDavid van Moolenbroek (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) {
462319e7a6dSDavid van Moolenbroek empty = 0;
463319e7a6dSDavid van Moolenbroek break;
464319e7a6dSDavid van Moolenbroek }
465319e7a6dSDavid van Moolenbroek closedir(dir);
466319e7a6dSDavid van Moolenbroek return (empty);
467319e7a6dSDavid van Moolenbroek }
468319e7a6dSDavid van Moolenbroek return (0);
469319e7a6dSDavid van Moolenbroek }
470319e7a6dSDavid van Moolenbroek
471319e7a6dSDavid van Moolenbroek PLAN *
c_empty(char *** argvp,int isok)472319e7a6dSDavid van Moolenbroek c_empty(char ***argvp, int isok)
473319e7a6dSDavid van Moolenbroek {
474319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
475319e7a6dSDavid van Moolenbroek
476319e7a6dSDavid van Moolenbroek return (palloc(N_EMPTY, f_empty));
477319e7a6dSDavid van Moolenbroek }
478319e7a6dSDavid van Moolenbroek
479319e7a6dSDavid van Moolenbroek /*
480319e7a6dSDavid van Moolenbroek * [-exec | -ok] utility [arg ... ] ; functions --
481319e7a6dSDavid van Moolenbroek * [-exec | -ok] utility [arg ... ] {} + functions --
482319e7a6dSDavid van Moolenbroek *
483319e7a6dSDavid van Moolenbroek * If the end of the primary expression is delimited by a
484319e7a6dSDavid van Moolenbroek * semicolon: true if the executed utility returns a zero value
485319e7a6dSDavid van Moolenbroek * as exit status. If "{}" occurs anywhere, it gets replaced by
486319e7a6dSDavid van Moolenbroek * the current pathname.
487319e7a6dSDavid van Moolenbroek *
488319e7a6dSDavid van Moolenbroek * If the end of the primary expression is delimited by a plus
489319e7a6dSDavid van Moolenbroek * sign: always true. Pathnames for which the primary is
490319e7a6dSDavid van Moolenbroek * evaluated shall be aggregated into sets. The utility will be
491319e7a6dSDavid van Moolenbroek * executed once per set, with "{}" replaced by the entire set of
492319e7a6dSDavid van Moolenbroek * pathnames (as if xargs). "{}" must appear last.
493319e7a6dSDavid van Moolenbroek *
494319e7a6dSDavid van Moolenbroek * The current directory for the execution of utility is the same
495319e7a6dSDavid van Moolenbroek * as the current directory when the find utility was started.
496319e7a6dSDavid van Moolenbroek *
497319e7a6dSDavid van Moolenbroek * The primary -ok is different in that it requests affirmation
498319e7a6dSDavid van Moolenbroek * of the user before executing the utility.
499319e7a6dSDavid van Moolenbroek */
500319e7a6dSDavid van Moolenbroek int
f_exec(PLAN * plan,FTSENT * entry)501319e7a6dSDavid van Moolenbroek f_exec(PLAN *plan, FTSENT *entry)
502319e7a6dSDavid van Moolenbroek {
503319e7a6dSDavid van Moolenbroek size_t cnt;
504319e7a6dSDavid van Moolenbroek int l;
505319e7a6dSDavid van Moolenbroek pid_t pid;
506319e7a6dSDavid van Moolenbroek int status;
507319e7a6dSDavid van Moolenbroek
508319e7a6dSDavid van Moolenbroek if (plan->flags & F_PLUSSET) {
509319e7a6dSDavid van Moolenbroek /*
510319e7a6dSDavid van Moolenbroek * Confirm sufficient buffer space, then copy the path
511319e7a6dSDavid van Moolenbroek * to the buffer.
512319e7a6dSDavid van Moolenbroek */
513319e7a6dSDavid van Moolenbroek l = strlen(entry->fts_path);
514319e7a6dSDavid van Moolenbroek if (plan->ep_p + l < plan->ep_ebp) {
515319e7a6dSDavid van Moolenbroek plan->ep_bxp[plan->ep_narg++] =
516319e7a6dSDavid van Moolenbroek strcpy(plan->ep_p, entry->fts_path);
517319e7a6dSDavid van Moolenbroek plan->ep_p += l + 1;
518319e7a6dSDavid van Moolenbroek
519319e7a6dSDavid van Moolenbroek if (plan->ep_narg == plan->ep_maxargs)
520319e7a6dSDavid van Moolenbroek run_f_exec(plan);
521319e7a6dSDavid van Moolenbroek } else {
522319e7a6dSDavid van Moolenbroek /*
523319e7a6dSDavid van Moolenbroek * Without sufficient space to copy in the next
524319e7a6dSDavid van Moolenbroek * argument, run the command to empty out the
525319e7a6dSDavid van Moolenbroek * buffer before re-attepting the copy.
526319e7a6dSDavid van Moolenbroek */
527319e7a6dSDavid van Moolenbroek run_f_exec(plan);
528319e7a6dSDavid van Moolenbroek if ((plan->ep_p + l < plan->ep_ebp)) {
529319e7a6dSDavid van Moolenbroek plan->ep_bxp[plan->ep_narg++]
530319e7a6dSDavid van Moolenbroek = strcpy(plan->ep_p, entry->fts_path);
531319e7a6dSDavid van Moolenbroek plan->ep_p += l + 1;
532319e7a6dSDavid van Moolenbroek } else
533319e7a6dSDavid van Moolenbroek errx(1, "insufficient space for argument");
534319e7a6dSDavid van Moolenbroek }
535319e7a6dSDavid van Moolenbroek return (1);
536319e7a6dSDavid van Moolenbroek } else {
537319e7a6dSDavid van Moolenbroek for (cnt = 0; plan->e_argv[cnt]; ++cnt)
538319e7a6dSDavid van Moolenbroek if (plan->e_len[cnt])
539319e7a6dSDavid van Moolenbroek brace_subst(plan->e_orig[cnt],
540319e7a6dSDavid van Moolenbroek &plan->e_argv[cnt],
541319e7a6dSDavid van Moolenbroek entry->fts_path,
542319e7a6dSDavid van Moolenbroek &plan->e_len[cnt]);
543319e7a6dSDavid van Moolenbroek if (plan->flags & F_NEEDOK && !queryuser(plan->e_argv))
544319e7a6dSDavid van Moolenbroek return (0);
545319e7a6dSDavid van Moolenbroek
546319e7a6dSDavid van Moolenbroek /* Don't mix output of command with find output. */
547319e7a6dSDavid van Moolenbroek fflush(stdout);
548319e7a6dSDavid van Moolenbroek fflush(stderr);
549319e7a6dSDavid van Moolenbroek
550319e7a6dSDavid van Moolenbroek switch (pid = vfork()) {
551319e7a6dSDavid van Moolenbroek case -1:
552319e7a6dSDavid van Moolenbroek err(1, "vfork");
553319e7a6dSDavid van Moolenbroek /* NOTREACHED */
554319e7a6dSDavid van Moolenbroek case 0:
555319e7a6dSDavid van Moolenbroek if (fchdir(dotfd)) {
556319e7a6dSDavid van Moolenbroek warn("chdir");
557319e7a6dSDavid van Moolenbroek _exit(1);
558319e7a6dSDavid van Moolenbroek }
559319e7a6dSDavid van Moolenbroek execvp(plan->e_argv[0], plan->e_argv);
560319e7a6dSDavid van Moolenbroek warn("%s", plan->e_argv[0]);
561319e7a6dSDavid van Moolenbroek _exit(1);
562319e7a6dSDavid van Moolenbroek }
563319e7a6dSDavid van Moolenbroek pid = waitpid(pid, &status, 0);
564319e7a6dSDavid van Moolenbroek return (pid != -1 && WIFEXITED(status)
565319e7a6dSDavid van Moolenbroek && !WEXITSTATUS(status));
566319e7a6dSDavid van Moolenbroek }
567319e7a6dSDavid van Moolenbroek }
568319e7a6dSDavid van Moolenbroek
569319e7a6dSDavid van Moolenbroek static void
run_f_exec(PLAN * plan)570319e7a6dSDavid van Moolenbroek run_f_exec(PLAN *plan)
571319e7a6dSDavid van Moolenbroek {
572319e7a6dSDavid van Moolenbroek pid_t pid;
573319e7a6dSDavid van Moolenbroek int rval, status;
574319e7a6dSDavid van Moolenbroek
575319e7a6dSDavid van Moolenbroek /* Ensure arg list is null terminated. */
576319e7a6dSDavid van Moolenbroek plan->ep_bxp[plan->ep_narg] = NULL;
577319e7a6dSDavid van Moolenbroek
578319e7a6dSDavid van Moolenbroek /* Don't mix output of command with find output. */
579319e7a6dSDavid van Moolenbroek fflush(stdout);
580319e7a6dSDavid van Moolenbroek fflush(stderr);
581319e7a6dSDavid van Moolenbroek
582319e7a6dSDavid van Moolenbroek switch (pid = vfork()) {
583319e7a6dSDavid van Moolenbroek case -1:
584319e7a6dSDavid van Moolenbroek err(1, "vfork");
585319e7a6dSDavid van Moolenbroek /* NOTREACHED */
586319e7a6dSDavid van Moolenbroek case 0:
587319e7a6dSDavid van Moolenbroek if (fchdir(dotfd)) {
588319e7a6dSDavid van Moolenbroek warn("chdir");
589319e7a6dSDavid van Moolenbroek _exit(1);
590319e7a6dSDavid van Moolenbroek }
591319e7a6dSDavid van Moolenbroek execvp(plan->e_argv[0], plan->e_argv);
592319e7a6dSDavid van Moolenbroek warn("%s", plan->e_argv[0]);
593319e7a6dSDavid van Moolenbroek _exit(1);
594319e7a6dSDavid van Moolenbroek }
595319e7a6dSDavid van Moolenbroek
596319e7a6dSDavid van Moolenbroek /* Clear out the argument list. */
597319e7a6dSDavid van Moolenbroek plan->ep_narg = 0;
598319e7a6dSDavid van Moolenbroek plan->ep_bxp[plan->ep_narg] = NULL;
599319e7a6dSDavid van Moolenbroek /* As well as the argument buffer. */
600319e7a6dSDavid van Moolenbroek plan->ep_p = plan->ep_bbp;
601319e7a6dSDavid van Moolenbroek *plan->ep_p = '\0';
602319e7a6dSDavid van Moolenbroek
603319e7a6dSDavid van Moolenbroek pid = waitpid(pid, &status, 0);
604319e7a6dSDavid van Moolenbroek if (WIFEXITED(status))
605319e7a6dSDavid van Moolenbroek rval = WEXITSTATUS(status);
606319e7a6dSDavid van Moolenbroek else
607319e7a6dSDavid van Moolenbroek rval = -1;
608319e7a6dSDavid van Moolenbroek
609319e7a6dSDavid van Moolenbroek /*
610319e7a6dSDavid van Moolenbroek * If we have a non-zero exit status, preserve it so find(1) can
611319e7a6dSDavid van Moolenbroek * later exit with it.
612319e7a6dSDavid van Moolenbroek */
613319e7a6dSDavid van Moolenbroek if (rval)
614319e7a6dSDavid van Moolenbroek plan->ep_rval = rval;
615319e7a6dSDavid van Moolenbroek }
616319e7a6dSDavid van Moolenbroek
617319e7a6dSDavid van Moolenbroek /*
618319e7a6dSDavid van Moolenbroek * c_exec --
619319e7a6dSDavid van Moolenbroek * build three parallel arrays, one with pointers to the strings passed
620319e7a6dSDavid van Moolenbroek * on the command line, one with (possibly duplicated) pointers to the
621319e7a6dSDavid van Moolenbroek * argv array, and one with integer values that are lengths of the
622319e7a6dSDavid van Moolenbroek * strings, but also flags meaning that the string has to be massaged.
623319e7a6dSDavid van Moolenbroek *
624319e7a6dSDavid van Moolenbroek * If -exec ... {} +, use only the first array, but make it large
625319e7a6dSDavid van Moolenbroek * enough to hold 5000 args (cf. src/usr.bin/xargs/xargs.c for a
626319e7a6dSDavid van Moolenbroek * discussion), and then allocate ARG_MAX - 4K of space for args.
627319e7a6dSDavid van Moolenbroek */
628319e7a6dSDavid van Moolenbroek PLAN *
c_exec(char *** argvp,int isok)629319e7a6dSDavid van Moolenbroek c_exec(char ***argvp, int isok)
630319e7a6dSDavid van Moolenbroek {
631319e7a6dSDavid van Moolenbroek PLAN *new; /* node returned */
632319e7a6dSDavid van Moolenbroek size_t cnt;
633319e7a6dSDavid van Moolenbroek int brace, lastbrace;
634319e7a6dSDavid van Moolenbroek char **argv, **ap, *p;
635319e7a6dSDavid van Moolenbroek
636319e7a6dSDavid van Moolenbroek isoutput = 1;
637319e7a6dSDavid van Moolenbroek
638319e7a6dSDavid van Moolenbroek new = palloc(N_EXEC, f_exec);
639319e7a6dSDavid van Moolenbroek if (isok)
640319e7a6dSDavid van Moolenbroek new->flags |= F_NEEDOK;
641319e7a6dSDavid van Moolenbroek
642319e7a6dSDavid van Moolenbroek /*
643319e7a6dSDavid van Moolenbroek * Terminate if we encounter an arg exactly equal to ";", or an
644319e7a6dSDavid van Moolenbroek * arg exactly equal to "+" following an arg exactly equal to
645319e7a6dSDavid van Moolenbroek * "{}".
646319e7a6dSDavid van Moolenbroek */
647319e7a6dSDavid van Moolenbroek for (ap = argv = *argvp, brace = 0;; ++ap) {
648319e7a6dSDavid van Moolenbroek if (!*ap)
649319e7a6dSDavid van Moolenbroek errx(1, "%s: no terminating \";\" or \"+\"",
650319e7a6dSDavid van Moolenbroek isok ? "-ok" : "-exec");
651319e7a6dSDavid van Moolenbroek lastbrace = brace;
652319e7a6dSDavid van Moolenbroek brace = 0;
653319e7a6dSDavid van Moolenbroek if (strcmp(*ap, "{}") == 0)
654319e7a6dSDavid van Moolenbroek brace = 1;
655319e7a6dSDavid van Moolenbroek if (strcmp(*ap, ";") == 0)
656319e7a6dSDavid van Moolenbroek break;
657319e7a6dSDavid van Moolenbroek if (strcmp(*ap, "+") == 0 && lastbrace) {
658319e7a6dSDavid van Moolenbroek new->flags |= F_PLUSSET;
659319e7a6dSDavid van Moolenbroek break;
660319e7a6dSDavid van Moolenbroek }
661319e7a6dSDavid van Moolenbroek }
662319e7a6dSDavid van Moolenbroek
663319e7a6dSDavid van Moolenbroek /*
664319e7a6dSDavid van Moolenbroek * POSIX says -ok ... {} + "need not be supported," and it does
665319e7a6dSDavid van Moolenbroek * not make much sense anyway.
666319e7a6dSDavid van Moolenbroek */
667319e7a6dSDavid van Moolenbroek if (new->flags & F_NEEDOK && new->flags & F_PLUSSET)
668319e7a6dSDavid van Moolenbroek errx(1, "-ok: terminating \"+\" not permitted.");
669319e7a6dSDavid van Moolenbroek
670319e7a6dSDavid van Moolenbroek if (new->flags & F_PLUSSET) {
671319e7a6dSDavid van Moolenbroek size_t c, bufsize;
672319e7a6dSDavid van Moolenbroek
673319e7a6dSDavid van Moolenbroek cnt = ap - *argvp - 1; /* units are words */
674319e7a6dSDavid van Moolenbroek new->ep_maxargs = 5000;
675319e7a6dSDavid van Moolenbroek new->e_argv = emalloc((cnt + new->ep_maxargs)
676319e7a6dSDavid van Moolenbroek * sizeof(*new->e_argv));
677319e7a6dSDavid van Moolenbroek
678319e7a6dSDavid van Moolenbroek /* We start stuffing arguments after the user's last one. */
679319e7a6dSDavid van Moolenbroek new->ep_bxp = &new->e_argv[cnt];
680319e7a6dSDavid van Moolenbroek new->ep_narg = 0;
681319e7a6dSDavid van Moolenbroek
682319e7a6dSDavid van Moolenbroek /*
683319e7a6dSDavid van Moolenbroek * Count up the space of the user's arguments, and
684319e7a6dSDavid van Moolenbroek * subtract that from what we allocate.
685319e7a6dSDavid van Moolenbroek */
686319e7a6dSDavid van Moolenbroek #define MAXARG (ARG_MAX - 4 * 1024)
687319e7a6dSDavid van Moolenbroek for (argv = *argvp, c = 0, cnt = 0;
688319e7a6dSDavid van Moolenbroek argv < ap;
689319e7a6dSDavid van Moolenbroek ++argv, ++cnt) {
690319e7a6dSDavid van Moolenbroek c += strlen(*argv) + 1;
691319e7a6dSDavid van Moolenbroek if (c >= MAXARG)
692319e7a6dSDavid van Moolenbroek errx(1, "Arguments too long");
693319e7a6dSDavid van Moolenbroek new->e_argv[cnt] = *argv;
694319e7a6dSDavid van Moolenbroek }
695319e7a6dSDavid van Moolenbroek bufsize = MAXARG - c;
696319e7a6dSDavid van Moolenbroek
697319e7a6dSDavid van Moolenbroek /*
698319e7a6dSDavid van Moolenbroek * Allocate, and then initialize current, base, and
699319e7a6dSDavid van Moolenbroek * end pointers.
700319e7a6dSDavid van Moolenbroek */
701319e7a6dSDavid van Moolenbroek new->ep_p = new->ep_bbp = emalloc(bufsize + 1);
702319e7a6dSDavid van Moolenbroek new->ep_ebp = new->ep_bbp + bufsize - 1;
703319e7a6dSDavid van Moolenbroek new->ep_rval = 0;
704319e7a6dSDavid van Moolenbroek } else { /* !F_PLUSSET */
705319e7a6dSDavid van Moolenbroek cnt = ap - *argvp + 1;
706319e7a6dSDavid van Moolenbroek new->e_argv = emalloc(cnt * sizeof(*new->e_argv));
707319e7a6dSDavid van Moolenbroek new->e_orig = emalloc(cnt * sizeof(*new->e_orig));
708319e7a6dSDavid van Moolenbroek new->e_len = emalloc(cnt * sizeof(*new->e_len));
709319e7a6dSDavid van Moolenbroek
710319e7a6dSDavid van Moolenbroek for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
711319e7a6dSDavid van Moolenbroek new->e_orig[cnt] = *argv;
712319e7a6dSDavid van Moolenbroek for (p = *argv; *p; ++p)
713319e7a6dSDavid van Moolenbroek if (p[0] == '{' && p[1] == '}') {
714319e7a6dSDavid van Moolenbroek new->e_argv[cnt] =
715319e7a6dSDavid van Moolenbroek emalloc(MAXPATHLEN);
716319e7a6dSDavid van Moolenbroek new->e_len[cnt] = MAXPATHLEN;
717319e7a6dSDavid van Moolenbroek break;
718319e7a6dSDavid van Moolenbroek }
719319e7a6dSDavid van Moolenbroek if (!*p) {
720319e7a6dSDavid van Moolenbroek new->e_argv[cnt] = *argv;
721319e7a6dSDavid van Moolenbroek new->e_len[cnt] = 0;
722319e7a6dSDavid van Moolenbroek }
723319e7a6dSDavid van Moolenbroek }
724319e7a6dSDavid van Moolenbroek new->e_orig[cnt] = NULL;
725319e7a6dSDavid van Moolenbroek }
726319e7a6dSDavid van Moolenbroek
727319e7a6dSDavid van Moolenbroek new->e_argv[cnt] = NULL;
728319e7a6dSDavid van Moolenbroek *argvp = argv + 1;
729319e7a6dSDavid van Moolenbroek return (new);
730319e7a6dSDavid van Moolenbroek }
731319e7a6dSDavid van Moolenbroek
732319e7a6dSDavid van Moolenbroek /*
733319e7a6dSDavid van Moolenbroek * -execdir utility [arg ... ] ; functions --
734319e7a6dSDavid van Moolenbroek *
735319e7a6dSDavid van Moolenbroek * True if the executed utility returns a zero value as exit status.
736319e7a6dSDavid van Moolenbroek * The end of the primary expression is delimited by a semicolon. If
737319e7a6dSDavid van Moolenbroek * "{}" occurs anywhere, it gets replaced by the unqualified pathname.
738319e7a6dSDavid van Moolenbroek * The current directory for the execution of utility is the same as
739319e7a6dSDavid van Moolenbroek * the directory where the file lives.
740319e7a6dSDavid van Moolenbroek */
741319e7a6dSDavid van Moolenbroek int
f_execdir(PLAN * plan,FTSENT * entry)742319e7a6dSDavid van Moolenbroek f_execdir(PLAN *plan, FTSENT *entry)
743319e7a6dSDavid van Moolenbroek {
744319e7a6dSDavid van Moolenbroek size_t cnt;
745319e7a6dSDavid van Moolenbroek pid_t pid;
746319e7a6dSDavid van Moolenbroek int status;
747319e7a6dSDavid van Moolenbroek char *file;
748319e7a6dSDavid van Moolenbroek
749319e7a6dSDavid van Moolenbroek /* XXX - if file/dir ends in '/' this will not work -- can it? */
750319e7a6dSDavid van Moolenbroek if ((file = strrchr(entry->fts_path, '/')))
751319e7a6dSDavid van Moolenbroek file++;
752319e7a6dSDavid van Moolenbroek else
753319e7a6dSDavid van Moolenbroek file = entry->fts_path;
754319e7a6dSDavid van Moolenbroek
755319e7a6dSDavid van Moolenbroek for (cnt = 0; plan->e_argv[cnt]; ++cnt)
756319e7a6dSDavid van Moolenbroek if (plan->e_len[cnt])
757319e7a6dSDavid van Moolenbroek brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
758319e7a6dSDavid van Moolenbroek file, &plan->e_len[cnt]);
759319e7a6dSDavid van Moolenbroek
760319e7a6dSDavid van Moolenbroek /* don't mix output of command with find output */
761319e7a6dSDavid van Moolenbroek fflush(stdout);
762319e7a6dSDavid van Moolenbroek fflush(stderr);
763319e7a6dSDavid van Moolenbroek
764319e7a6dSDavid van Moolenbroek switch (pid = vfork()) {
765319e7a6dSDavid van Moolenbroek case -1:
766319e7a6dSDavid van Moolenbroek err(1, "fork");
767319e7a6dSDavid van Moolenbroek /* NOTREACHED */
768319e7a6dSDavid van Moolenbroek case 0:
769319e7a6dSDavid van Moolenbroek execvp(plan->e_argv[0], plan->e_argv);
770319e7a6dSDavid van Moolenbroek warn("%s", plan->e_argv[0]);
771319e7a6dSDavid van Moolenbroek _exit(1);
772319e7a6dSDavid van Moolenbroek }
773319e7a6dSDavid van Moolenbroek pid = waitpid(pid, &status, 0);
774319e7a6dSDavid van Moolenbroek return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
775319e7a6dSDavid van Moolenbroek }
776319e7a6dSDavid van Moolenbroek
777319e7a6dSDavid van Moolenbroek /*
778319e7a6dSDavid van Moolenbroek * c_execdir --
779319e7a6dSDavid van Moolenbroek * build three parallel arrays, one with pointers to the strings passed
780319e7a6dSDavid van Moolenbroek * on the command line, one with (possibly duplicated) pointers to the
781319e7a6dSDavid van Moolenbroek * argv array, and one with integer values that are lengths of the
782319e7a6dSDavid van Moolenbroek * strings, but also flags meaning that the string has to be massaged.
783319e7a6dSDavid van Moolenbroek */
784319e7a6dSDavid van Moolenbroek PLAN *
c_execdir(char *** argvp,int isok)785319e7a6dSDavid van Moolenbroek c_execdir(char ***argvp, int isok)
786319e7a6dSDavid van Moolenbroek {
787319e7a6dSDavid van Moolenbroek PLAN *new; /* node returned */
788319e7a6dSDavid van Moolenbroek size_t cnt;
789319e7a6dSDavid van Moolenbroek char **argv, **ap, *p;
790319e7a6dSDavid van Moolenbroek
791319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
792319e7a6dSDavid van Moolenbroek isoutput = 1;
793319e7a6dSDavid van Moolenbroek
794319e7a6dSDavid van Moolenbroek new = palloc(N_EXECDIR, f_execdir);
795319e7a6dSDavid van Moolenbroek
796319e7a6dSDavid van Moolenbroek for (ap = argv = *argvp;; ++ap) {
797319e7a6dSDavid van Moolenbroek if (!*ap)
798319e7a6dSDavid van Moolenbroek errx(1,
799319e7a6dSDavid van Moolenbroek "-execdir: no terminating \";\"");
800319e7a6dSDavid van Moolenbroek if (**ap == ';')
801319e7a6dSDavid van Moolenbroek break;
802319e7a6dSDavid van Moolenbroek }
803319e7a6dSDavid van Moolenbroek
804319e7a6dSDavid van Moolenbroek cnt = ap - *argvp + 1;
805319e7a6dSDavid van Moolenbroek new->e_argv = emalloc(cnt * sizeof(*new->e_argv));
806319e7a6dSDavid van Moolenbroek new->e_orig = emalloc(cnt * sizeof(*new->e_orig));
807319e7a6dSDavid van Moolenbroek new->e_len = emalloc(cnt * sizeof(*new->e_len));
808319e7a6dSDavid van Moolenbroek
809319e7a6dSDavid van Moolenbroek for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
810319e7a6dSDavid van Moolenbroek new->e_orig[cnt] = *argv;
811319e7a6dSDavid van Moolenbroek for (p = *argv; *p; ++p)
812319e7a6dSDavid van Moolenbroek if (p[0] == '{' && p[1] == '}') {
813319e7a6dSDavid van Moolenbroek new->e_argv[cnt] = emalloc(MAXPATHLEN);
814319e7a6dSDavid van Moolenbroek new->e_len[cnt] = MAXPATHLEN;
815319e7a6dSDavid van Moolenbroek break;
816319e7a6dSDavid van Moolenbroek }
817319e7a6dSDavid van Moolenbroek if (!*p) {
818319e7a6dSDavid van Moolenbroek new->e_argv[cnt] = *argv;
819319e7a6dSDavid van Moolenbroek new->e_len[cnt] = 0;
820319e7a6dSDavid van Moolenbroek }
821319e7a6dSDavid van Moolenbroek }
822319e7a6dSDavid van Moolenbroek new->e_argv[cnt] = new->e_orig[cnt] = NULL;
823319e7a6dSDavid van Moolenbroek
824319e7a6dSDavid van Moolenbroek *argvp = argv + 1;
825319e7a6dSDavid van Moolenbroek return (new);
826319e7a6dSDavid van Moolenbroek }
827319e7a6dSDavid van Moolenbroek
828319e7a6dSDavid van Moolenbroek PLAN *
c_exit(char *** argvp,int isok)829319e7a6dSDavid van Moolenbroek c_exit(char ***argvp, int isok)
830319e7a6dSDavid van Moolenbroek {
831319e7a6dSDavid van Moolenbroek char *arg = **argvp;
832319e7a6dSDavid van Moolenbroek PLAN *new;
833319e7a6dSDavid van Moolenbroek
834319e7a6dSDavid van Moolenbroek /* not technically true, but otherwise '-print' is implied */
835319e7a6dSDavid van Moolenbroek isoutput = 1;
836319e7a6dSDavid van Moolenbroek
837319e7a6dSDavid van Moolenbroek new = palloc(N_EXIT, f_always_true);
838319e7a6dSDavid van Moolenbroek
839319e7a6dSDavid van Moolenbroek if (arg) {
840319e7a6dSDavid van Moolenbroek (*argvp)++;
841319e7a6dSDavid van Moolenbroek new->exit_val = find_parsenum(new, "-exit", arg, NULL);
842319e7a6dSDavid van Moolenbroek } else
843319e7a6dSDavid van Moolenbroek new->exit_val = 0;
844319e7a6dSDavid van Moolenbroek
845319e7a6dSDavid van Moolenbroek return (new);
846319e7a6dSDavid van Moolenbroek }
847319e7a6dSDavid van Moolenbroek
848319e7a6dSDavid van Moolenbroek
849319e7a6dSDavid van Moolenbroek /*
850319e7a6dSDavid van Moolenbroek * -false function
851319e7a6dSDavid van Moolenbroek */
852319e7a6dSDavid van Moolenbroek int
f_false(PLAN * plan,FTSENT * entry)853319e7a6dSDavid van Moolenbroek f_false(PLAN *plan, FTSENT *entry)
854319e7a6dSDavid van Moolenbroek {
855319e7a6dSDavid van Moolenbroek
856319e7a6dSDavid van Moolenbroek return (0);
857319e7a6dSDavid van Moolenbroek }
858319e7a6dSDavid van Moolenbroek
859319e7a6dSDavid van Moolenbroek PLAN *
c_false(char *** argvp,int isok)860319e7a6dSDavid van Moolenbroek c_false(char ***argvp, int isok)
861319e7a6dSDavid van Moolenbroek {
862319e7a6dSDavid van Moolenbroek return (palloc(N_FALSE, f_false));
863319e7a6dSDavid van Moolenbroek }
864319e7a6dSDavid van Moolenbroek
865319e7a6dSDavid van Moolenbroek
866319e7a6dSDavid van Moolenbroek /*
867319e7a6dSDavid van Moolenbroek * -flags [-]flags functions --
868319e7a6dSDavid van Moolenbroek */
869319e7a6dSDavid van Moolenbroek int
f_flags(PLAN * plan,FTSENT * entry)870319e7a6dSDavid van Moolenbroek f_flags(PLAN *plan, FTSENT *entry)
871319e7a6dSDavid van Moolenbroek {
872319e7a6dSDavid van Moolenbroek u_int32_t flags;
873319e7a6dSDavid van Moolenbroek
874319e7a6dSDavid van Moolenbroek flags = entry->fts_statp->st_flags;
875319e7a6dSDavid van Moolenbroek if (plan->flags == F_ATLEAST)
876319e7a6dSDavid van Moolenbroek return ((plan->f_data | flags) == flags);
877319e7a6dSDavid van Moolenbroek else
878319e7a6dSDavid van Moolenbroek return (flags == plan->f_data);
879319e7a6dSDavid van Moolenbroek /* NOTREACHED */
880319e7a6dSDavid van Moolenbroek }
881319e7a6dSDavid van Moolenbroek
882319e7a6dSDavid van Moolenbroek PLAN *
c_flags(char *** argvp,int isok)883319e7a6dSDavid van Moolenbroek c_flags(char ***argvp, int isok)
884319e7a6dSDavid van Moolenbroek {
885319e7a6dSDavid van Moolenbroek char *flags = **argvp;
886319e7a6dSDavid van Moolenbroek PLAN *new;
887319e7a6dSDavid van Moolenbroek u_long flagset;
888319e7a6dSDavid van Moolenbroek
889319e7a6dSDavid van Moolenbroek (*argvp)++;
890319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
891319e7a6dSDavid van Moolenbroek
892319e7a6dSDavid van Moolenbroek new = palloc(N_FLAGS, f_flags);
893319e7a6dSDavid van Moolenbroek
894319e7a6dSDavid van Moolenbroek if (*flags == '-') {
895319e7a6dSDavid van Moolenbroek new->flags = F_ATLEAST;
896319e7a6dSDavid van Moolenbroek ++flags;
897319e7a6dSDavid van Moolenbroek }
898319e7a6dSDavid van Moolenbroek
899319e7a6dSDavid van Moolenbroek flagset = 0;
900319e7a6dSDavid van Moolenbroek if ((strcmp(flags, "none") != 0) &&
901319e7a6dSDavid van Moolenbroek (string_to_flags(&flags, &flagset, NULL) != 0))
902319e7a6dSDavid van Moolenbroek errx(1, "-flags: %s: illegal flags string", flags);
903319e7a6dSDavid van Moolenbroek new->f_data = flagset;
904319e7a6dSDavid van Moolenbroek return (new);
905319e7a6dSDavid van Moolenbroek }
906319e7a6dSDavid van Moolenbroek
907319e7a6dSDavid van Moolenbroek /*
908319e7a6dSDavid van Moolenbroek * -follow functions --
909319e7a6dSDavid van Moolenbroek *
910319e7a6dSDavid van Moolenbroek * Always true, causes symbolic links to be followed on a global
911319e7a6dSDavid van Moolenbroek * basis.
912319e7a6dSDavid van Moolenbroek */
913319e7a6dSDavid van Moolenbroek PLAN *
c_follow(char *** argvp,int isok)914319e7a6dSDavid van Moolenbroek c_follow(char ***argvp, int isok)
915319e7a6dSDavid van Moolenbroek {
916319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_PHYSICAL;
917319e7a6dSDavid van Moolenbroek ftsoptions |= FTS_LOGICAL;
918319e7a6dSDavid van Moolenbroek
919319e7a6dSDavid van Moolenbroek return (palloc(N_FOLLOW, f_always_true));
920319e7a6dSDavid van Moolenbroek }
921319e7a6dSDavid van Moolenbroek
922319e7a6dSDavid van Moolenbroek /* -fprint functions --
923319e7a6dSDavid van Moolenbroek *
924319e7a6dSDavid van Moolenbroek * Causes the current pathame to be written to the defined output file.
925319e7a6dSDavid van Moolenbroek */
926319e7a6dSDavid van Moolenbroek int
f_fprint(PLAN * plan,FTSENT * entry)927319e7a6dSDavid van Moolenbroek f_fprint(PLAN *plan, FTSENT *entry)
928319e7a6dSDavid van Moolenbroek {
929319e7a6dSDavid van Moolenbroek
930319e7a6dSDavid van Moolenbroek if (-1 == fprintf(plan->fprint_file, "%s\n", entry->fts_path))
931319e7a6dSDavid van Moolenbroek warn("fprintf");
932319e7a6dSDavid van Moolenbroek
933319e7a6dSDavid van Moolenbroek return(1);
934319e7a6dSDavid van Moolenbroek
935319e7a6dSDavid van Moolenbroek /* no descriptors are closed; they will be closed by
936319e7a6dSDavid van Moolenbroek operating system when this find command exits. */
937319e7a6dSDavid van Moolenbroek }
938319e7a6dSDavid van Moolenbroek
939319e7a6dSDavid van Moolenbroek PLAN *
c_fprint(char *** argvp,int isok)940319e7a6dSDavid van Moolenbroek c_fprint(char ***argvp, int isok)
941319e7a6dSDavid van Moolenbroek {
942319e7a6dSDavid van Moolenbroek PLAN *new;
943319e7a6dSDavid van Moolenbroek
944319e7a6dSDavid van Moolenbroek isoutput = 1; /* do not assume -print */
945319e7a6dSDavid van Moolenbroek
946319e7a6dSDavid van Moolenbroek new = palloc(N_FPRINT, f_fprint);
947319e7a6dSDavid van Moolenbroek
948319e7a6dSDavid van Moolenbroek if (NULL == (new->fprint_file = fopen(**argvp, "w")))
949319e7a6dSDavid van Moolenbroek err(1, "-fprint: %s: cannot create file", **argvp);
950319e7a6dSDavid van Moolenbroek
951319e7a6dSDavid van Moolenbroek (*argvp)++;
952319e7a6dSDavid van Moolenbroek return (new);
953319e7a6dSDavid van Moolenbroek }
954319e7a6dSDavid van Moolenbroek
955319e7a6dSDavid van Moolenbroek /*
956319e7a6dSDavid van Moolenbroek * -fstype functions --
957319e7a6dSDavid van Moolenbroek *
958319e7a6dSDavid van Moolenbroek * True if the file is of a certain type.
959319e7a6dSDavid van Moolenbroek */
960319e7a6dSDavid van Moolenbroek int
f_fstype(PLAN * plan,FTSENT * entry)961319e7a6dSDavid van Moolenbroek f_fstype(PLAN *plan, FTSENT *entry)
962319e7a6dSDavid van Moolenbroek {
963319e7a6dSDavid van Moolenbroek static dev_t curdev; /* need a guaranteed illegal dev value */
964319e7a6dSDavid van Moolenbroek static int first = 1;
965319e7a6dSDavid van Moolenbroek struct statvfs sb;
966319e7a6dSDavid van Moolenbroek static short val;
967319e7a6dSDavid van Moolenbroek static char fstype[sizeof(sb.f_fstypename)];
968319e7a6dSDavid van Moolenbroek char *p, save[2];
969319e7a6dSDavid van Moolenbroek
970319e7a6dSDavid van Moolenbroek memset(&save, 0, sizeof save); /* XXX gcc */
971319e7a6dSDavid van Moolenbroek
972319e7a6dSDavid van Moolenbroek /* Only check when we cross mount point. */
973319e7a6dSDavid van Moolenbroek if (first || curdev != entry->fts_statp->st_dev) {
974319e7a6dSDavid van Moolenbroek curdev = entry->fts_statp->st_dev;
975319e7a6dSDavid van Moolenbroek
976319e7a6dSDavid van Moolenbroek /*
977319e7a6dSDavid van Moolenbroek * Statfs follows symlinks; find wants the link's file system,
978319e7a6dSDavid van Moolenbroek * not where it points.
979319e7a6dSDavid van Moolenbroek */
980319e7a6dSDavid van Moolenbroek if (entry->fts_info == FTS_SL ||
981319e7a6dSDavid van Moolenbroek entry->fts_info == FTS_SLNONE) {
982319e7a6dSDavid van Moolenbroek if ((p = strrchr(entry->fts_accpath, '/')) != NULL)
983319e7a6dSDavid van Moolenbroek ++p;
984319e7a6dSDavid van Moolenbroek else
985319e7a6dSDavid van Moolenbroek p = entry->fts_accpath;
986319e7a6dSDavid van Moolenbroek save[0] = p[0];
987319e7a6dSDavid van Moolenbroek p[0] = '.';
988319e7a6dSDavid van Moolenbroek save[1] = p[1];
989319e7a6dSDavid van Moolenbroek p[1] = '\0';
990319e7a6dSDavid van Moolenbroek
991319e7a6dSDavid van Moolenbroek } else
992319e7a6dSDavid van Moolenbroek p = NULL;
993319e7a6dSDavid van Moolenbroek
994319e7a6dSDavid van Moolenbroek if (statvfs(entry->fts_accpath, &sb))
995319e7a6dSDavid van Moolenbroek err(1, "%s", entry->fts_accpath);
996319e7a6dSDavid van Moolenbroek
997319e7a6dSDavid van Moolenbroek if (p) {
998319e7a6dSDavid van Moolenbroek p[0] = save[0];
999319e7a6dSDavid van Moolenbroek p[1] = save[1];
1000319e7a6dSDavid van Moolenbroek }
1001319e7a6dSDavid van Moolenbroek
1002319e7a6dSDavid van Moolenbroek first = 0;
1003319e7a6dSDavid van Moolenbroek
1004319e7a6dSDavid van Moolenbroek /*
1005319e7a6dSDavid van Moolenbroek * Further tests may need both of these values, so
1006319e7a6dSDavid van Moolenbroek * always copy both of them.
1007319e7a6dSDavid van Moolenbroek */
1008319e7a6dSDavid van Moolenbroek val = sb.f_flag;
1009319e7a6dSDavid van Moolenbroek strlcpy(fstype, sb.f_fstypename, sizeof(fstype));
1010319e7a6dSDavid van Moolenbroek }
1011319e7a6dSDavid van Moolenbroek switch (plan->flags) {
1012319e7a6dSDavid van Moolenbroek case F_MTFLAG:
1013319e7a6dSDavid van Moolenbroek return (val & plan->mt_data);
1014319e7a6dSDavid van Moolenbroek case F_MTTYPE:
1015319e7a6dSDavid van Moolenbroek return (strncmp(fstype, plan->c_data, sizeof(fstype)) == 0);
1016319e7a6dSDavid van Moolenbroek default:
1017319e7a6dSDavid van Moolenbroek abort();
1018319e7a6dSDavid van Moolenbroek }
1019319e7a6dSDavid van Moolenbroek }
1020319e7a6dSDavid van Moolenbroek
1021319e7a6dSDavid van Moolenbroek PLAN *
c_fstype(char *** argvp,int isok)1022319e7a6dSDavid van Moolenbroek c_fstype(char ***argvp, int isok)
1023319e7a6dSDavid van Moolenbroek {
1024319e7a6dSDavid van Moolenbroek char *arg = **argvp;
1025319e7a6dSDavid van Moolenbroek PLAN *new;
1026319e7a6dSDavid van Moolenbroek
1027319e7a6dSDavid van Moolenbroek (*argvp)++;
1028319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1029319e7a6dSDavid van Moolenbroek
1030319e7a6dSDavid van Moolenbroek new = palloc(N_FSTYPE, f_fstype);
1031319e7a6dSDavid van Moolenbroek
1032319e7a6dSDavid van Moolenbroek switch (*arg) {
1033319e7a6dSDavid van Moolenbroek case 'l':
1034319e7a6dSDavid van Moolenbroek if (!strcmp(arg, "local")) {
1035319e7a6dSDavid van Moolenbroek new->flags = F_MTFLAG;
1036319e7a6dSDavid van Moolenbroek new->mt_data = MNT_LOCAL;
1037319e7a6dSDavid van Moolenbroek return (new);
1038319e7a6dSDavid van Moolenbroek }
1039319e7a6dSDavid van Moolenbroek break;
1040319e7a6dSDavid van Moolenbroek case 'r':
1041319e7a6dSDavid van Moolenbroek if (!strcmp(arg, "rdonly")) {
1042319e7a6dSDavid van Moolenbroek new->flags = F_MTFLAG;
1043319e7a6dSDavid van Moolenbroek new->mt_data = MNT_RDONLY;
1044319e7a6dSDavid van Moolenbroek return (new);
1045319e7a6dSDavid van Moolenbroek }
1046319e7a6dSDavid van Moolenbroek break;
1047319e7a6dSDavid van Moolenbroek }
1048319e7a6dSDavid van Moolenbroek
1049319e7a6dSDavid van Moolenbroek new->flags = F_MTTYPE;
1050319e7a6dSDavid van Moolenbroek new->c_data = arg;
1051319e7a6dSDavid van Moolenbroek return (new);
1052319e7a6dSDavid van Moolenbroek }
1053319e7a6dSDavid van Moolenbroek
1054319e7a6dSDavid van Moolenbroek /*
1055319e7a6dSDavid van Moolenbroek * -group gname functions --
1056319e7a6dSDavid van Moolenbroek *
1057319e7a6dSDavid van Moolenbroek * True if the file belongs to the group gname. If gname is numeric and
1058319e7a6dSDavid van Moolenbroek * an equivalent of the getgrnam() function does not return a valid group
1059319e7a6dSDavid van Moolenbroek * name, gname is taken as a group ID.
1060319e7a6dSDavid van Moolenbroek */
1061319e7a6dSDavid van Moolenbroek int
f_group(PLAN * plan,FTSENT * entry)1062319e7a6dSDavid van Moolenbroek f_group(PLAN *plan, FTSENT *entry)
1063319e7a6dSDavid van Moolenbroek {
1064319e7a6dSDavid van Moolenbroek
1065319e7a6dSDavid van Moolenbroek return (entry->fts_statp->st_gid == plan->g_data);
1066319e7a6dSDavid van Moolenbroek }
1067319e7a6dSDavid van Moolenbroek
1068319e7a6dSDavid van Moolenbroek PLAN *
c_group(char *** argvp,int isok)1069319e7a6dSDavid van Moolenbroek c_group(char ***argvp, int isok)
1070319e7a6dSDavid van Moolenbroek {
1071319e7a6dSDavid van Moolenbroek char *gname = **argvp;
1072319e7a6dSDavid van Moolenbroek PLAN *new;
1073319e7a6dSDavid van Moolenbroek struct group *g;
1074319e7a6dSDavid van Moolenbroek gid_t gid;
1075319e7a6dSDavid van Moolenbroek
1076319e7a6dSDavid van Moolenbroek (*argvp)++;
1077319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1078319e7a6dSDavid van Moolenbroek
1079319e7a6dSDavid van Moolenbroek g = getgrnam(gname);
1080319e7a6dSDavid van Moolenbroek if (g == NULL) {
1081319e7a6dSDavid van Moolenbroek gid = atoi(gname);
1082319e7a6dSDavid van Moolenbroek if (gid == 0 && gname[0] != '0')
1083319e7a6dSDavid van Moolenbroek errx(1, "-group: %s: no such group", gname);
1084319e7a6dSDavid van Moolenbroek } else
1085319e7a6dSDavid van Moolenbroek gid = g->gr_gid;
1086319e7a6dSDavid van Moolenbroek
1087319e7a6dSDavid van Moolenbroek new = palloc(N_GROUP, f_group);
1088319e7a6dSDavid van Moolenbroek new->g_data = gid;
1089319e7a6dSDavid van Moolenbroek return (new);
1090319e7a6dSDavid van Moolenbroek }
1091319e7a6dSDavid van Moolenbroek
1092319e7a6dSDavid van Moolenbroek /*
1093319e7a6dSDavid van Moolenbroek * -inum n functions --
1094319e7a6dSDavid van Moolenbroek *
1095319e7a6dSDavid van Moolenbroek * True if the file has inode # n.
1096319e7a6dSDavid van Moolenbroek */
1097319e7a6dSDavid van Moolenbroek int
f_inum(PLAN * plan,FTSENT * entry)1098319e7a6dSDavid van Moolenbroek f_inum(PLAN *plan, FTSENT *entry)
1099319e7a6dSDavid van Moolenbroek {
1100319e7a6dSDavid van Moolenbroek
1101319e7a6dSDavid van Moolenbroek COMPARE(entry->fts_statp->st_ino, plan->i_data);
1102319e7a6dSDavid van Moolenbroek }
1103319e7a6dSDavid van Moolenbroek
1104319e7a6dSDavid van Moolenbroek PLAN *
c_inum(char *** argvp,int isok)1105319e7a6dSDavid van Moolenbroek c_inum(char ***argvp, int isok)
1106319e7a6dSDavid van Moolenbroek {
1107319e7a6dSDavid van Moolenbroek char *arg = **argvp;
1108319e7a6dSDavid van Moolenbroek PLAN *new;
1109319e7a6dSDavid van Moolenbroek
1110319e7a6dSDavid van Moolenbroek (*argvp)++;
1111319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1112319e7a6dSDavid van Moolenbroek
1113319e7a6dSDavid van Moolenbroek new = palloc(N_INUM, f_inum);
1114319e7a6dSDavid van Moolenbroek new->i_data = find_parsenum(new, "-inum", arg, NULL);
1115319e7a6dSDavid van Moolenbroek return (new);
1116319e7a6dSDavid van Moolenbroek }
1117319e7a6dSDavid van Moolenbroek
1118319e7a6dSDavid van Moolenbroek /*
1119319e7a6dSDavid van Moolenbroek * -links n functions --
1120319e7a6dSDavid van Moolenbroek *
1121319e7a6dSDavid van Moolenbroek * True if the file has n links.
1122319e7a6dSDavid van Moolenbroek */
1123319e7a6dSDavid van Moolenbroek int
f_links(PLAN * plan,FTSENT * entry)1124319e7a6dSDavid van Moolenbroek f_links(PLAN *plan, FTSENT *entry)
1125319e7a6dSDavid van Moolenbroek {
1126319e7a6dSDavid van Moolenbroek
1127319e7a6dSDavid van Moolenbroek COMPARE(entry->fts_statp->st_nlink, plan->l_data);
1128319e7a6dSDavid van Moolenbroek }
1129319e7a6dSDavid van Moolenbroek
1130319e7a6dSDavid van Moolenbroek PLAN *
c_links(char *** argvp,int isok)1131319e7a6dSDavid van Moolenbroek c_links(char ***argvp, int isok)
1132319e7a6dSDavid van Moolenbroek {
1133319e7a6dSDavid van Moolenbroek char *arg = **argvp;
1134319e7a6dSDavid van Moolenbroek PLAN *new;
1135319e7a6dSDavid van Moolenbroek
1136319e7a6dSDavid van Moolenbroek (*argvp)++;
1137319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1138319e7a6dSDavid van Moolenbroek
1139319e7a6dSDavid van Moolenbroek new = palloc(N_LINKS, f_links);
1140319e7a6dSDavid van Moolenbroek new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
1141319e7a6dSDavid van Moolenbroek return (new);
1142319e7a6dSDavid van Moolenbroek }
1143319e7a6dSDavid van Moolenbroek
1144319e7a6dSDavid van Moolenbroek /*
1145319e7a6dSDavid van Moolenbroek * -ls functions --
1146319e7a6dSDavid van Moolenbroek *
1147319e7a6dSDavid van Moolenbroek * Always true - prints the current entry to stdout in "ls" format.
1148319e7a6dSDavid van Moolenbroek */
1149319e7a6dSDavid van Moolenbroek int
f_ls(PLAN * plan,FTSENT * entry)1150319e7a6dSDavid van Moolenbroek f_ls(PLAN *plan, FTSENT *entry)
1151319e7a6dSDavid van Moolenbroek {
1152319e7a6dSDavid van Moolenbroek
1153319e7a6dSDavid van Moolenbroek printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
1154319e7a6dSDavid van Moolenbroek return (1);
1155319e7a6dSDavid van Moolenbroek }
1156319e7a6dSDavid van Moolenbroek
1157319e7a6dSDavid van Moolenbroek PLAN *
c_ls(char *** argvp,int isok)1158319e7a6dSDavid van Moolenbroek c_ls(char ***argvp, int isok)
1159319e7a6dSDavid van Moolenbroek {
1160319e7a6dSDavid van Moolenbroek
1161319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1162319e7a6dSDavid van Moolenbroek isoutput = 1;
1163319e7a6dSDavid van Moolenbroek
1164319e7a6dSDavid van Moolenbroek return (palloc(N_LS, f_ls));
1165319e7a6dSDavid van Moolenbroek }
1166319e7a6dSDavid van Moolenbroek
1167319e7a6dSDavid van Moolenbroek /*
1168319e7a6dSDavid van Moolenbroek * - maxdepth n functions --
1169319e7a6dSDavid van Moolenbroek *
1170319e7a6dSDavid van Moolenbroek * True if the current search depth is less than or equal to the
1171319e7a6dSDavid van Moolenbroek * maximum depth specified
1172319e7a6dSDavid van Moolenbroek */
1173319e7a6dSDavid van Moolenbroek int
f_maxdepth(PLAN * plan,FTSENT * entry)1174319e7a6dSDavid van Moolenbroek f_maxdepth(PLAN *plan, FTSENT *entry)
1175319e7a6dSDavid van Moolenbroek {
1176319e7a6dSDavid van Moolenbroek extern FTS *tree;
1177319e7a6dSDavid van Moolenbroek
1178319e7a6dSDavid van Moolenbroek if (entry->fts_level >= plan->max_data)
1179319e7a6dSDavid van Moolenbroek fts_set(tree, entry, FTS_SKIP);
1180319e7a6dSDavid van Moolenbroek return (entry->fts_level <= plan->max_data);
1181319e7a6dSDavid van Moolenbroek }
1182319e7a6dSDavid van Moolenbroek
1183319e7a6dSDavid van Moolenbroek PLAN *
c_maxdepth(char *** argvp,int isok)1184319e7a6dSDavid van Moolenbroek c_maxdepth(char ***argvp, int isok)
1185319e7a6dSDavid van Moolenbroek {
1186319e7a6dSDavid van Moolenbroek char *arg = **argvp;
1187319e7a6dSDavid van Moolenbroek PLAN *new;
1188319e7a6dSDavid van Moolenbroek
1189319e7a6dSDavid van Moolenbroek (*argvp)++;
1190319e7a6dSDavid van Moolenbroek new = palloc(N_MAXDEPTH, f_maxdepth);
1191319e7a6dSDavid van Moolenbroek new->max_data = atoi(arg);
1192319e7a6dSDavid van Moolenbroek return (new);
1193319e7a6dSDavid van Moolenbroek }
1194319e7a6dSDavid van Moolenbroek
1195319e7a6dSDavid van Moolenbroek /*
1196319e7a6dSDavid van Moolenbroek * - mindepth n functions --
1197319e7a6dSDavid van Moolenbroek *
1198319e7a6dSDavid van Moolenbroek * True if the current search depth is greater than or equal to the
1199319e7a6dSDavid van Moolenbroek * minimum depth specified
1200319e7a6dSDavid van Moolenbroek */
1201319e7a6dSDavid van Moolenbroek int
f_mindepth(PLAN * plan,FTSENT * entry)1202319e7a6dSDavid van Moolenbroek f_mindepth(PLAN *plan, FTSENT *entry)
1203319e7a6dSDavid van Moolenbroek {
1204319e7a6dSDavid van Moolenbroek return (entry->fts_level >= plan->min_data);
1205319e7a6dSDavid van Moolenbroek }
1206319e7a6dSDavid van Moolenbroek
1207319e7a6dSDavid van Moolenbroek PLAN *
c_mindepth(char *** argvp,int isok)1208319e7a6dSDavid van Moolenbroek c_mindepth(char ***argvp, int isok)
1209319e7a6dSDavid van Moolenbroek {
1210319e7a6dSDavid van Moolenbroek char *arg = **argvp;
1211319e7a6dSDavid van Moolenbroek PLAN *new;
1212319e7a6dSDavid van Moolenbroek
1213319e7a6dSDavid van Moolenbroek (*argvp)++;
1214319e7a6dSDavid van Moolenbroek new = palloc(N_MINDEPTH, f_mindepth);
1215319e7a6dSDavid van Moolenbroek new->min_data = atoi(arg);
1216319e7a6dSDavid van Moolenbroek return (new);
1217319e7a6dSDavid van Moolenbroek }
1218319e7a6dSDavid van Moolenbroek
1219319e7a6dSDavid van Moolenbroek /*
1220319e7a6dSDavid van Moolenbroek * -mmin n functions --
1221319e7a6dSDavid van Moolenbroek *
1222319e7a6dSDavid van Moolenbroek * True if the difference between the file modification time and the
1223319e7a6dSDavid van Moolenbroek * current time is n 24 hour periods.
1224319e7a6dSDavid van Moolenbroek */
1225319e7a6dSDavid van Moolenbroek int
f_mmin(PLAN * plan,FTSENT * entry)1226319e7a6dSDavid van Moolenbroek f_mmin(PLAN *plan, FTSENT *entry)
1227319e7a6dSDavid van Moolenbroek {
1228319e7a6dSDavid van Moolenbroek COMPARE((now - entry->fts_statp->st_mtime + SECSPERMIN - 1) /
1229319e7a6dSDavid van Moolenbroek SECSPERMIN, plan->t_data);
1230319e7a6dSDavid van Moolenbroek }
1231319e7a6dSDavid van Moolenbroek
1232319e7a6dSDavid van Moolenbroek PLAN *
c_mmin(char *** argvp,int isok)1233319e7a6dSDavid van Moolenbroek c_mmin(char ***argvp, int isok)
1234319e7a6dSDavid van Moolenbroek {
1235319e7a6dSDavid van Moolenbroek char *arg = **argvp;
1236319e7a6dSDavid van Moolenbroek PLAN *new;
1237319e7a6dSDavid van Moolenbroek
1238319e7a6dSDavid van Moolenbroek (*argvp)++;
1239319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1240319e7a6dSDavid van Moolenbroek
1241319e7a6dSDavid van Moolenbroek new = palloc(N_MMIN, f_mmin);
1242319e7a6dSDavid van Moolenbroek new->t_data = find_parsenum(new, "-mmin", arg, NULL);
1243319e7a6dSDavid van Moolenbroek TIME_CORRECT(new, N_MMIN);
1244319e7a6dSDavid van Moolenbroek return (new);
1245319e7a6dSDavid van Moolenbroek }
1246319e7a6dSDavid van Moolenbroek
1247319e7a6dSDavid van Moolenbroek /*
1248319e7a6dSDavid van Moolenbroek * -mtime n functions --
1249319e7a6dSDavid van Moolenbroek *
1250319e7a6dSDavid van Moolenbroek * True if the difference between the file modification time and the
1251319e7a6dSDavid van Moolenbroek * current time is n 24 hour periods.
1252319e7a6dSDavid van Moolenbroek */
1253319e7a6dSDavid van Moolenbroek int
f_mtime(PLAN * plan,FTSENT * entry)1254319e7a6dSDavid van Moolenbroek f_mtime(PLAN *plan, FTSENT *entry)
1255319e7a6dSDavid van Moolenbroek {
1256319e7a6dSDavid van Moolenbroek COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
1257319e7a6dSDavid van Moolenbroek SECSPERDAY, plan->t_data);
1258319e7a6dSDavid van Moolenbroek }
1259319e7a6dSDavid van Moolenbroek
1260319e7a6dSDavid van Moolenbroek PLAN *
c_mtime(char *** argvp,int isok)1261319e7a6dSDavid van Moolenbroek c_mtime(char ***argvp, int isok)
1262319e7a6dSDavid van Moolenbroek {
1263319e7a6dSDavid van Moolenbroek char *arg = **argvp;
1264319e7a6dSDavid van Moolenbroek PLAN *new;
1265319e7a6dSDavid van Moolenbroek
1266319e7a6dSDavid van Moolenbroek (*argvp)++;
1267319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1268319e7a6dSDavid van Moolenbroek
1269319e7a6dSDavid van Moolenbroek new = palloc(N_MTIME, f_mtime);
1270319e7a6dSDavid van Moolenbroek new->t_data = find_parsenum(new, "-mtime", arg, NULL);
1271319e7a6dSDavid van Moolenbroek TIME_CORRECT(new, N_MTIME);
1272319e7a6dSDavid van Moolenbroek return (new);
1273319e7a6dSDavid van Moolenbroek }
1274319e7a6dSDavid van Moolenbroek
1275319e7a6dSDavid van Moolenbroek /*
1276319e7a6dSDavid van Moolenbroek * -name functions --
1277319e7a6dSDavid van Moolenbroek *
1278319e7a6dSDavid van Moolenbroek * True if the basename of the filename being examined
1279319e7a6dSDavid van Moolenbroek * matches pattern using Pattern Matching Notation S3.14
1280319e7a6dSDavid van Moolenbroek */
1281319e7a6dSDavid van Moolenbroek int
f_name(PLAN * plan,FTSENT * entry)1282319e7a6dSDavid van Moolenbroek f_name(PLAN *plan, FTSENT *entry)
1283319e7a6dSDavid van Moolenbroek {
1284319e7a6dSDavid van Moolenbroek
1285319e7a6dSDavid van Moolenbroek return (!fnmatch(plan->c_data, entry->fts_name, 0));
1286319e7a6dSDavid van Moolenbroek }
1287319e7a6dSDavid van Moolenbroek
1288319e7a6dSDavid van Moolenbroek PLAN *
c_name(char *** argvp,int isok)1289319e7a6dSDavid van Moolenbroek c_name(char ***argvp, int isok)
1290319e7a6dSDavid van Moolenbroek {
1291319e7a6dSDavid van Moolenbroek char *pattern = **argvp;
1292319e7a6dSDavid van Moolenbroek PLAN *new;
1293319e7a6dSDavid van Moolenbroek
1294319e7a6dSDavid van Moolenbroek (*argvp)++;
1295319e7a6dSDavid van Moolenbroek new = palloc(N_NAME, f_name);
1296319e7a6dSDavid van Moolenbroek new->c_data = pattern;
1297319e7a6dSDavid van Moolenbroek return (new);
1298319e7a6dSDavid van Moolenbroek }
1299319e7a6dSDavid van Moolenbroek
1300319e7a6dSDavid van Moolenbroek /*
1301319e7a6dSDavid van Moolenbroek * -iname functions --
1302319e7a6dSDavid van Moolenbroek *
1303319e7a6dSDavid van Moolenbroek * Similar to -name, but does case insensitive matching
1304319e7a6dSDavid van Moolenbroek *
1305319e7a6dSDavid van Moolenbroek */
1306319e7a6dSDavid van Moolenbroek int
f_iname(PLAN * plan,FTSENT * entry)1307319e7a6dSDavid van Moolenbroek f_iname(PLAN *plan, FTSENT *entry)
1308319e7a6dSDavid van Moolenbroek {
1309319e7a6dSDavid van Moolenbroek return (!fnmatch(plan->c_data, entry->fts_name, FNM_CASEFOLD));
1310319e7a6dSDavid van Moolenbroek }
1311319e7a6dSDavid van Moolenbroek
1312319e7a6dSDavid van Moolenbroek PLAN *
c_iname(char *** argvp,int isok)1313319e7a6dSDavid van Moolenbroek c_iname(char ***argvp, int isok)
1314319e7a6dSDavid van Moolenbroek {
1315319e7a6dSDavid van Moolenbroek char *pattern = **argvp;
1316319e7a6dSDavid van Moolenbroek PLAN *new;
1317319e7a6dSDavid van Moolenbroek
1318319e7a6dSDavid van Moolenbroek (*argvp)++;
1319319e7a6dSDavid van Moolenbroek new = palloc(N_INAME, f_iname);
1320319e7a6dSDavid van Moolenbroek new->c_data = pattern;
1321319e7a6dSDavid van Moolenbroek return (new);
1322319e7a6dSDavid van Moolenbroek }
1323319e7a6dSDavid van Moolenbroek
1324319e7a6dSDavid van Moolenbroek /*
1325319e7a6dSDavid van Moolenbroek * -newer file functions --
1326319e7a6dSDavid van Moolenbroek *
1327319e7a6dSDavid van Moolenbroek * True if the current file has been modified more recently
1328319e7a6dSDavid van Moolenbroek * than the modification time of the file named by the pathname
1329319e7a6dSDavid van Moolenbroek * file.
1330319e7a6dSDavid van Moolenbroek */
1331319e7a6dSDavid van Moolenbroek int
f_newer(PLAN * plan,FTSENT * entry)1332319e7a6dSDavid van Moolenbroek f_newer(PLAN *plan, FTSENT *entry)
1333319e7a6dSDavid van Moolenbroek {
1334319e7a6dSDavid van Moolenbroek
1335319e7a6dSDavid van Moolenbroek return timespeccmp(&entry->fts_statp->st_mtim, &plan->ts_data, >);
1336319e7a6dSDavid van Moolenbroek }
1337319e7a6dSDavid van Moolenbroek
1338319e7a6dSDavid van Moolenbroek PLAN *
c_newer(char *** argvp,int isok)1339319e7a6dSDavid van Moolenbroek c_newer(char ***argvp, int isok)
1340319e7a6dSDavid van Moolenbroek {
1341319e7a6dSDavid van Moolenbroek char *filename = **argvp;
1342319e7a6dSDavid van Moolenbroek PLAN *new;
1343319e7a6dSDavid van Moolenbroek struct stat sb;
1344319e7a6dSDavid van Moolenbroek
1345319e7a6dSDavid van Moolenbroek (*argvp)++;
1346319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1347319e7a6dSDavid van Moolenbroek
1348319e7a6dSDavid van Moolenbroek if (stat(filename, &sb))
1349319e7a6dSDavid van Moolenbroek err(1, "%s", filename);
1350319e7a6dSDavid van Moolenbroek new = palloc(N_NEWER, f_newer);
1351319e7a6dSDavid van Moolenbroek new->ts_data = sb.st_mtim;
1352319e7a6dSDavid van Moolenbroek return (new);
1353319e7a6dSDavid van Moolenbroek }
1354319e7a6dSDavid van Moolenbroek
1355319e7a6dSDavid van Moolenbroek /*
1356319e7a6dSDavid van Moolenbroek * -nogroup functions --
1357319e7a6dSDavid van Moolenbroek *
1358319e7a6dSDavid van Moolenbroek * True if file belongs to a user ID for which the equivalent
1359319e7a6dSDavid van Moolenbroek * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
1360319e7a6dSDavid van Moolenbroek */
1361319e7a6dSDavid van Moolenbroek int
f_nogroup(PLAN * plan,FTSENT * entry)1362319e7a6dSDavid van Moolenbroek f_nogroup(PLAN *plan, FTSENT *entry)
1363319e7a6dSDavid van Moolenbroek {
1364319e7a6dSDavid van Moolenbroek
1365319e7a6dSDavid van Moolenbroek return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
1366319e7a6dSDavid van Moolenbroek }
1367319e7a6dSDavid van Moolenbroek
1368319e7a6dSDavid van Moolenbroek PLAN *
c_nogroup(char *** argvp,int isok)1369319e7a6dSDavid van Moolenbroek c_nogroup(char ***argvp, int isok)
1370319e7a6dSDavid van Moolenbroek {
1371319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1372319e7a6dSDavid van Moolenbroek
1373319e7a6dSDavid van Moolenbroek return (palloc(N_NOGROUP, f_nogroup));
1374319e7a6dSDavid van Moolenbroek }
1375319e7a6dSDavid van Moolenbroek
1376319e7a6dSDavid van Moolenbroek /*
1377319e7a6dSDavid van Moolenbroek * -nouser functions --
1378319e7a6dSDavid van Moolenbroek *
1379319e7a6dSDavid van Moolenbroek * True if file belongs to a user ID for which the equivalent
1380319e7a6dSDavid van Moolenbroek * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
1381319e7a6dSDavid van Moolenbroek */
1382319e7a6dSDavid van Moolenbroek int
f_nouser(PLAN * plan,FTSENT * entry)1383319e7a6dSDavid van Moolenbroek f_nouser(PLAN *plan, FTSENT *entry)
1384319e7a6dSDavid van Moolenbroek {
1385319e7a6dSDavid van Moolenbroek
1386319e7a6dSDavid van Moolenbroek return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
1387319e7a6dSDavid van Moolenbroek }
1388319e7a6dSDavid van Moolenbroek
1389319e7a6dSDavid van Moolenbroek PLAN *
c_nouser(char *** argvp,int isok)1390319e7a6dSDavid van Moolenbroek c_nouser(char ***argvp, int isok)
1391319e7a6dSDavid van Moolenbroek {
1392319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1393319e7a6dSDavid van Moolenbroek
1394319e7a6dSDavid van Moolenbroek return (palloc(N_NOUSER, f_nouser));
1395319e7a6dSDavid van Moolenbroek }
1396319e7a6dSDavid van Moolenbroek
1397319e7a6dSDavid van Moolenbroek /*
1398319e7a6dSDavid van Moolenbroek * -path functions --
1399319e7a6dSDavid van Moolenbroek *
1400319e7a6dSDavid van Moolenbroek * True if the path of the filename being examined
1401319e7a6dSDavid van Moolenbroek * matches pattern using Pattern Matching Notation S3.14
1402319e7a6dSDavid van Moolenbroek */
1403319e7a6dSDavid van Moolenbroek int
f_path(PLAN * plan,FTSENT * entry)1404319e7a6dSDavid van Moolenbroek f_path(PLAN *plan, FTSENT *entry)
1405319e7a6dSDavid van Moolenbroek {
1406319e7a6dSDavid van Moolenbroek
1407319e7a6dSDavid van Moolenbroek return (!fnmatch(plan->c_data, entry->fts_path, 0));
1408319e7a6dSDavid van Moolenbroek }
1409319e7a6dSDavid van Moolenbroek
1410319e7a6dSDavid van Moolenbroek PLAN *
c_path(char *** argvp,int isok)1411319e7a6dSDavid van Moolenbroek c_path(char ***argvp, int isok)
1412319e7a6dSDavid van Moolenbroek {
1413319e7a6dSDavid van Moolenbroek char *pattern = **argvp;
1414319e7a6dSDavid van Moolenbroek PLAN *new;
1415319e7a6dSDavid van Moolenbroek
1416319e7a6dSDavid van Moolenbroek (*argvp)++;
1417319e7a6dSDavid van Moolenbroek new = palloc(N_NAME, f_path);
1418319e7a6dSDavid van Moolenbroek new->c_data = pattern;
1419319e7a6dSDavid van Moolenbroek return (new);
1420319e7a6dSDavid van Moolenbroek }
1421319e7a6dSDavid van Moolenbroek
1422319e7a6dSDavid van Moolenbroek /*
1423319e7a6dSDavid van Moolenbroek * -perm functions --
1424319e7a6dSDavid van Moolenbroek *
1425319e7a6dSDavid van Moolenbroek * The mode argument is used to represent file mode bits. If it starts
1426319e7a6dSDavid van Moolenbroek * with a leading digit, it's treated as an octal mode, otherwise as a
1427319e7a6dSDavid van Moolenbroek * symbolic mode.
1428319e7a6dSDavid van Moolenbroek */
1429319e7a6dSDavid van Moolenbroek int
f_perm(PLAN * plan,FTSENT * entry)1430319e7a6dSDavid van Moolenbroek f_perm(PLAN *plan, FTSENT *entry)
1431319e7a6dSDavid van Moolenbroek {
1432319e7a6dSDavid van Moolenbroek mode_t mode;
1433319e7a6dSDavid van Moolenbroek
1434319e7a6dSDavid van Moolenbroek mode = entry->fts_statp->st_mode &
1435319e7a6dSDavid van Moolenbroek (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
1436319e7a6dSDavid van Moolenbroek if (plan->flags == F_ATLEAST)
1437319e7a6dSDavid van Moolenbroek return ((plan->m_data | mode) == mode);
1438319e7a6dSDavid van Moolenbroek else
1439319e7a6dSDavid van Moolenbroek return (mode == plan->m_data);
1440319e7a6dSDavid van Moolenbroek /* NOTREACHED */
1441319e7a6dSDavid van Moolenbroek }
1442319e7a6dSDavid van Moolenbroek
1443319e7a6dSDavid van Moolenbroek PLAN *
c_perm(char *** argvp,int isok)1444319e7a6dSDavid van Moolenbroek c_perm(char ***argvp, int isok)
1445319e7a6dSDavid van Moolenbroek {
1446319e7a6dSDavid van Moolenbroek char *perm = **argvp;
1447319e7a6dSDavid van Moolenbroek PLAN *new;
1448319e7a6dSDavid van Moolenbroek mode_t *set;
1449319e7a6dSDavid van Moolenbroek
1450319e7a6dSDavid van Moolenbroek (*argvp)++;
1451319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1452319e7a6dSDavid van Moolenbroek
1453319e7a6dSDavid van Moolenbroek new = palloc(N_PERM, f_perm);
1454319e7a6dSDavid van Moolenbroek
1455319e7a6dSDavid van Moolenbroek if (*perm == '-') {
1456319e7a6dSDavid van Moolenbroek new->flags = F_ATLEAST;
1457319e7a6dSDavid van Moolenbroek ++perm;
1458319e7a6dSDavid van Moolenbroek }
1459319e7a6dSDavid van Moolenbroek
1460319e7a6dSDavid van Moolenbroek if ((set = setmode(perm)) == NULL)
1461319e7a6dSDavid van Moolenbroek err(1, "-perm: Cannot set file mode `%s'", perm);
1462319e7a6dSDavid van Moolenbroek
1463319e7a6dSDavid van Moolenbroek new->m_data = getmode(set, 0);
1464319e7a6dSDavid van Moolenbroek free(set);
1465319e7a6dSDavid van Moolenbroek return (new);
1466319e7a6dSDavid van Moolenbroek }
1467319e7a6dSDavid van Moolenbroek
1468319e7a6dSDavid van Moolenbroek /*
1469319e7a6dSDavid van Moolenbroek * -print functions --
1470319e7a6dSDavid van Moolenbroek *
1471319e7a6dSDavid van Moolenbroek * Always true, causes the current pathame to be written to
1472319e7a6dSDavid van Moolenbroek * standard output.
1473319e7a6dSDavid van Moolenbroek */
1474319e7a6dSDavid van Moolenbroek int
f_print(PLAN * plan,FTSENT * entry)1475319e7a6dSDavid van Moolenbroek f_print(PLAN *plan, FTSENT *entry)
1476319e7a6dSDavid van Moolenbroek {
1477319e7a6dSDavid van Moolenbroek
1478319e7a6dSDavid van Moolenbroek (void)printf("%s\n", entry->fts_path);
1479319e7a6dSDavid van Moolenbroek return (1);
1480319e7a6dSDavid van Moolenbroek }
1481319e7a6dSDavid van Moolenbroek
1482319e7a6dSDavid van Moolenbroek int
f_print0(PLAN * plan,FTSENT * entry)1483319e7a6dSDavid van Moolenbroek f_print0(PLAN *plan, FTSENT *entry)
1484319e7a6dSDavid van Moolenbroek {
1485319e7a6dSDavid van Moolenbroek
1486319e7a6dSDavid van Moolenbroek (void)fputs(entry->fts_path, stdout);
1487319e7a6dSDavid van Moolenbroek (void)fputc('\0', stdout);
1488319e7a6dSDavid van Moolenbroek return (1);
1489319e7a6dSDavid van Moolenbroek }
1490319e7a6dSDavid van Moolenbroek
1491319e7a6dSDavid van Moolenbroek int
f_printx(PLAN * plan,FTSENT * entry)1492319e7a6dSDavid van Moolenbroek f_printx(PLAN *plan, FTSENT *entry)
1493319e7a6dSDavid van Moolenbroek {
1494319e7a6dSDavid van Moolenbroek char *cp;
1495319e7a6dSDavid van Moolenbroek
1496319e7a6dSDavid van Moolenbroek for (cp = entry->fts_path; *cp; cp++) {
1497319e7a6dSDavid van Moolenbroek if (*cp == '\'' || *cp == '\"' || *cp == ' ' ||
1498319e7a6dSDavid van Moolenbroek *cp == '$' || *cp == '`' ||
1499319e7a6dSDavid van Moolenbroek *cp == '\t' || *cp == '\n' || *cp == '\\')
1500319e7a6dSDavid van Moolenbroek fputc('\\', stdout);
1501319e7a6dSDavid van Moolenbroek
1502319e7a6dSDavid van Moolenbroek fputc(*cp, stdout);
1503319e7a6dSDavid van Moolenbroek }
1504319e7a6dSDavid van Moolenbroek
1505319e7a6dSDavid van Moolenbroek fputc('\n', stdout);
1506319e7a6dSDavid van Moolenbroek return (1);
1507319e7a6dSDavid van Moolenbroek }
1508319e7a6dSDavid van Moolenbroek
1509319e7a6dSDavid van Moolenbroek PLAN *
c_print(char *** argvp,int isok)1510319e7a6dSDavid van Moolenbroek c_print(char ***argvp, int isok)
1511319e7a6dSDavid van Moolenbroek {
1512319e7a6dSDavid van Moolenbroek
1513319e7a6dSDavid van Moolenbroek isoutput = 1;
1514319e7a6dSDavid van Moolenbroek
1515319e7a6dSDavid van Moolenbroek return (palloc(N_PRINT, f_print));
1516319e7a6dSDavid van Moolenbroek }
1517319e7a6dSDavid van Moolenbroek
1518319e7a6dSDavid van Moolenbroek PLAN *
c_print0(char *** argvp,int isok)1519319e7a6dSDavid van Moolenbroek c_print0(char ***argvp, int isok)
1520319e7a6dSDavid van Moolenbroek {
1521319e7a6dSDavid van Moolenbroek
1522319e7a6dSDavid van Moolenbroek isoutput = 1;
1523319e7a6dSDavid van Moolenbroek
1524319e7a6dSDavid van Moolenbroek return (palloc(N_PRINT0, f_print0));
1525319e7a6dSDavid van Moolenbroek }
1526319e7a6dSDavid van Moolenbroek
1527319e7a6dSDavid van Moolenbroek PLAN *
c_printx(char *** argvp,int isok)1528319e7a6dSDavid van Moolenbroek c_printx(char ***argvp, int isok)
1529319e7a6dSDavid van Moolenbroek {
1530319e7a6dSDavid van Moolenbroek
1531319e7a6dSDavid van Moolenbroek isoutput = 1;
1532319e7a6dSDavid van Moolenbroek
1533319e7a6dSDavid van Moolenbroek return (palloc(N_PRINTX, f_printx));
1534319e7a6dSDavid van Moolenbroek }
1535319e7a6dSDavid van Moolenbroek
1536319e7a6dSDavid van Moolenbroek /*
1537319e7a6dSDavid van Moolenbroek * -prune functions --
1538319e7a6dSDavid van Moolenbroek *
1539319e7a6dSDavid van Moolenbroek * Prune a portion of the hierarchy.
1540319e7a6dSDavid van Moolenbroek */
1541319e7a6dSDavid van Moolenbroek int
f_prune(PLAN * plan,FTSENT * entry)1542319e7a6dSDavid van Moolenbroek f_prune(PLAN *plan, FTSENT *entry)
1543319e7a6dSDavid van Moolenbroek {
1544319e7a6dSDavid van Moolenbroek if (fts_set(tree, entry, FTS_SKIP))
1545319e7a6dSDavid van Moolenbroek err(1, "%s", entry->fts_path);
1546319e7a6dSDavid van Moolenbroek return (1);
1547319e7a6dSDavid van Moolenbroek }
1548319e7a6dSDavid van Moolenbroek
1549319e7a6dSDavid van Moolenbroek PLAN *
c_prune(char *** argvp,int isok)1550319e7a6dSDavid van Moolenbroek c_prune(char ***argvp, int isok)
1551319e7a6dSDavid van Moolenbroek {
1552319e7a6dSDavid van Moolenbroek
1553319e7a6dSDavid van Moolenbroek return (palloc(N_PRUNE, f_prune));
1554319e7a6dSDavid van Moolenbroek }
1555319e7a6dSDavid van Moolenbroek
1556319e7a6dSDavid van Moolenbroek /*
1557319e7a6dSDavid van Moolenbroek * -regex regexp (and related) functions --
1558319e7a6dSDavid van Moolenbroek *
1559319e7a6dSDavid van Moolenbroek * True if the complete file path matches the regular expression regexp.
1560319e7a6dSDavid van Moolenbroek * For -regex, regexp is a case-sensitive (basic) regular expression.
1561319e7a6dSDavid van Moolenbroek * For -iregex, regexp is a case-insensitive (basic) regular expression.
1562319e7a6dSDavid van Moolenbroek */
1563319e7a6dSDavid van Moolenbroek int
f_regex(PLAN * plan,FTSENT * entry)1564319e7a6dSDavid van Moolenbroek f_regex(PLAN *plan, FTSENT *entry)
1565319e7a6dSDavid van Moolenbroek {
1566319e7a6dSDavid van Moolenbroek
1567319e7a6dSDavid van Moolenbroek return (regexec(&plan->regexp_data, entry->fts_path, 0, NULL, 0) == 0);
1568319e7a6dSDavid van Moolenbroek }
1569319e7a6dSDavid van Moolenbroek
1570319e7a6dSDavid van Moolenbroek static PLAN *
c_regex_common(char *** argvp,int isok,enum ntype type,bool icase)1571319e7a6dSDavid van Moolenbroek c_regex_common(char ***argvp, int isok, enum ntype type, bool icase)
1572319e7a6dSDavid van Moolenbroek {
1573319e7a6dSDavid van Moolenbroek char errbuf[LINE_MAX];
1574319e7a6dSDavid van Moolenbroek regex_t reg;
1575319e7a6dSDavid van Moolenbroek char *regexp = **argvp;
1576319e7a6dSDavid van Moolenbroek char *lineregexp;
1577319e7a6dSDavid van Moolenbroek PLAN *new;
1578319e7a6dSDavid van Moolenbroek int rv;
1579319e7a6dSDavid van Moolenbroek size_t len;
1580319e7a6dSDavid van Moolenbroek
1581319e7a6dSDavid van Moolenbroek (*argvp)++;
1582319e7a6dSDavid van Moolenbroek
1583319e7a6dSDavid van Moolenbroek len = strlen(regexp) + 1 + 6;
1584319e7a6dSDavid van Moolenbroek lineregexp = malloc(len); /* max needed */
1585319e7a6dSDavid van Moolenbroek if (lineregexp == NULL)
1586319e7a6dSDavid van Moolenbroek err(1, NULL);
1587319e7a6dSDavid van Moolenbroek snprintf(lineregexp, len, "^%s(%s%s)$",
1588319e7a6dSDavid van Moolenbroek (regcomp_flags & REG_EXTENDED) ? "" : "\\", regexp,
1589319e7a6dSDavid van Moolenbroek (regcomp_flags & REG_EXTENDED) ? "" : "\\");
1590319e7a6dSDavid van Moolenbroek rv = regcomp(®, lineregexp, REG_NOSUB|regcomp_flags|
1591319e7a6dSDavid van Moolenbroek (icase ? REG_ICASE : 0));
1592319e7a6dSDavid van Moolenbroek free(lineregexp);
1593319e7a6dSDavid van Moolenbroek if (rv != 0) {
1594319e7a6dSDavid van Moolenbroek regerror(rv, ®, errbuf, sizeof errbuf);
1595319e7a6dSDavid van Moolenbroek errx(1, "regexp %s: %s", regexp, errbuf);
1596319e7a6dSDavid van Moolenbroek }
1597319e7a6dSDavid van Moolenbroek
1598319e7a6dSDavid van Moolenbroek new = palloc(type, f_regex);
1599319e7a6dSDavid van Moolenbroek new->regexp_data = reg;
1600319e7a6dSDavid van Moolenbroek return (new);
1601319e7a6dSDavid van Moolenbroek }
1602319e7a6dSDavid van Moolenbroek
1603319e7a6dSDavid van Moolenbroek PLAN *
c_regex(char *** argvp,int isok)1604319e7a6dSDavid van Moolenbroek c_regex(char ***argvp, int isok)
1605319e7a6dSDavid van Moolenbroek {
1606319e7a6dSDavid van Moolenbroek
1607319e7a6dSDavid van Moolenbroek return (c_regex_common(argvp, isok, N_REGEX, false));
1608319e7a6dSDavid van Moolenbroek }
1609319e7a6dSDavid van Moolenbroek
1610319e7a6dSDavid van Moolenbroek PLAN *
c_iregex(char *** argvp,int isok)1611319e7a6dSDavid van Moolenbroek c_iregex(char ***argvp, int isok)
1612319e7a6dSDavid van Moolenbroek {
1613319e7a6dSDavid van Moolenbroek
1614319e7a6dSDavid van Moolenbroek return (c_regex_common(argvp, isok, N_IREGEX, true));
1615319e7a6dSDavid van Moolenbroek }
1616319e7a6dSDavid van Moolenbroek
1617319e7a6dSDavid van Moolenbroek /*
1618319e7a6dSDavid van Moolenbroek * -size n[c] functions --
1619319e7a6dSDavid van Moolenbroek *
1620319e7a6dSDavid van Moolenbroek * True if the file size in bytes, divided by an implementation defined
1621319e7a6dSDavid van Moolenbroek * value and rounded up to the next integer, is n. If n is followed by
1622319e7a6dSDavid van Moolenbroek * a c, the size is in bytes.
1623319e7a6dSDavid van Moolenbroek */
1624319e7a6dSDavid van Moolenbroek #define FIND_SIZE 512
1625319e7a6dSDavid van Moolenbroek static int divsize = 1;
1626319e7a6dSDavid van Moolenbroek
1627319e7a6dSDavid van Moolenbroek int
f_size(PLAN * plan,FTSENT * entry)1628319e7a6dSDavid van Moolenbroek f_size(PLAN *plan, FTSENT *entry)
1629319e7a6dSDavid van Moolenbroek {
1630319e7a6dSDavid van Moolenbroek off_t size;
1631319e7a6dSDavid van Moolenbroek
1632319e7a6dSDavid van Moolenbroek size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
1633319e7a6dSDavid van Moolenbroek FIND_SIZE : entry->fts_statp->st_size;
1634319e7a6dSDavid van Moolenbroek COMPARE(size, plan->o_data);
1635319e7a6dSDavid van Moolenbroek }
1636319e7a6dSDavid van Moolenbroek
1637319e7a6dSDavid van Moolenbroek PLAN *
c_size(char *** argvp,int isok)1638319e7a6dSDavid van Moolenbroek c_size(char ***argvp, int isok)
1639319e7a6dSDavid van Moolenbroek {
1640319e7a6dSDavid van Moolenbroek char *arg = **argvp;
1641319e7a6dSDavid van Moolenbroek PLAN *new;
1642319e7a6dSDavid van Moolenbroek char endch;
1643319e7a6dSDavid van Moolenbroek
1644319e7a6dSDavid van Moolenbroek (*argvp)++;
1645319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1646319e7a6dSDavid van Moolenbroek
1647319e7a6dSDavid van Moolenbroek new = palloc(N_SIZE, f_size);
1648319e7a6dSDavid van Moolenbroek endch = 'c';
1649319e7a6dSDavid van Moolenbroek new->o_data = find_parsenum(new, "-size", arg, &endch);
1650319e7a6dSDavid van Moolenbroek if (endch == 'c')
1651319e7a6dSDavid van Moolenbroek divsize = 0;
1652319e7a6dSDavid van Moolenbroek return (new);
1653319e7a6dSDavid van Moolenbroek }
1654319e7a6dSDavid van Moolenbroek
1655319e7a6dSDavid van Moolenbroek /*
1656319e7a6dSDavid van Moolenbroek * -type c functions --
1657319e7a6dSDavid van Moolenbroek *
1658319e7a6dSDavid van Moolenbroek * True if the type of the file is c, where c is b, c, d, p, f or w
1659319e7a6dSDavid van Moolenbroek * for block special file, character special file, directory, FIFO,
1660319e7a6dSDavid van Moolenbroek * regular file or whiteout respectively.
1661319e7a6dSDavid van Moolenbroek */
1662319e7a6dSDavid van Moolenbroek int
f_type(PLAN * plan,FTSENT * entry)1663319e7a6dSDavid van Moolenbroek f_type(PLAN *plan, FTSENT *entry)
1664319e7a6dSDavid van Moolenbroek {
1665319e7a6dSDavid van Moolenbroek
1666319e7a6dSDavid van Moolenbroek return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
1667319e7a6dSDavid van Moolenbroek }
1668319e7a6dSDavid van Moolenbroek
1669319e7a6dSDavid van Moolenbroek PLAN *
c_type(char *** argvp,int isok)1670319e7a6dSDavid van Moolenbroek c_type(char ***argvp, int isok)
1671319e7a6dSDavid van Moolenbroek {
1672319e7a6dSDavid van Moolenbroek char *typestring = **argvp;
1673319e7a6dSDavid van Moolenbroek PLAN *new;
1674319e7a6dSDavid van Moolenbroek mode_t mask = (mode_t)0;
1675319e7a6dSDavid van Moolenbroek
1676319e7a6dSDavid van Moolenbroek (*argvp)++;
1677319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1678319e7a6dSDavid van Moolenbroek
1679319e7a6dSDavid van Moolenbroek switch (typestring[0]) {
1680319e7a6dSDavid van Moolenbroek case 'b':
1681319e7a6dSDavid van Moolenbroek mask = S_IFBLK;
1682319e7a6dSDavid van Moolenbroek break;
1683319e7a6dSDavid van Moolenbroek case 'c':
1684319e7a6dSDavid van Moolenbroek mask = S_IFCHR;
1685319e7a6dSDavid van Moolenbroek break;
1686319e7a6dSDavid van Moolenbroek case 'd':
1687319e7a6dSDavid van Moolenbroek mask = S_IFDIR;
1688319e7a6dSDavid van Moolenbroek break;
1689319e7a6dSDavid van Moolenbroek case 'f':
1690319e7a6dSDavid van Moolenbroek mask = S_IFREG;
1691319e7a6dSDavid van Moolenbroek break;
1692319e7a6dSDavid van Moolenbroek case 'l':
1693319e7a6dSDavid van Moolenbroek mask = S_IFLNK;
1694319e7a6dSDavid van Moolenbroek break;
1695319e7a6dSDavid van Moolenbroek case 'p':
1696319e7a6dSDavid van Moolenbroek mask = S_IFIFO;
1697319e7a6dSDavid van Moolenbroek break;
1698319e7a6dSDavid van Moolenbroek case 's':
1699319e7a6dSDavid van Moolenbroek mask = S_IFSOCK;
1700319e7a6dSDavid van Moolenbroek break;
1701319e7a6dSDavid van Moolenbroek #ifdef S_IFWHT
1702319e7a6dSDavid van Moolenbroek case 'W':
1703319e7a6dSDavid van Moolenbroek case 'w':
1704319e7a6dSDavid van Moolenbroek mask = S_IFWHT;
1705319e7a6dSDavid van Moolenbroek #ifdef FTS_WHITEOUT
1706319e7a6dSDavid van Moolenbroek ftsoptions |= FTS_WHITEOUT;
1707319e7a6dSDavid van Moolenbroek #endif
1708319e7a6dSDavid van Moolenbroek break;
1709319e7a6dSDavid van Moolenbroek #endif /* S_IFWHT */
1710319e7a6dSDavid van Moolenbroek default:
1711319e7a6dSDavid van Moolenbroek errx(1, "-type: %s: unknown type", typestring);
1712319e7a6dSDavid van Moolenbroek }
1713319e7a6dSDavid van Moolenbroek
1714319e7a6dSDavid van Moolenbroek new = palloc(N_TYPE, f_type);
1715319e7a6dSDavid van Moolenbroek new->m_data = mask;
1716319e7a6dSDavid van Moolenbroek return (new);
1717319e7a6dSDavid van Moolenbroek }
1718319e7a6dSDavid van Moolenbroek
1719319e7a6dSDavid van Moolenbroek /*
1720319e7a6dSDavid van Moolenbroek * -user uname functions --
1721319e7a6dSDavid van Moolenbroek *
1722319e7a6dSDavid van Moolenbroek * True if the file belongs to the user uname. If uname is numeric and
1723319e7a6dSDavid van Moolenbroek * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
1724319e7a6dSDavid van Moolenbroek * return a valid user name, uname is taken as a user ID.
1725319e7a6dSDavid van Moolenbroek */
1726319e7a6dSDavid van Moolenbroek int
f_user(PLAN * plan,FTSENT * entry)1727319e7a6dSDavid van Moolenbroek f_user(PLAN *plan, FTSENT *entry)
1728319e7a6dSDavid van Moolenbroek {
1729319e7a6dSDavid van Moolenbroek
1730319e7a6dSDavid van Moolenbroek COMPARE(entry->fts_statp->st_uid, plan->u_data);
1731319e7a6dSDavid van Moolenbroek }
1732319e7a6dSDavid van Moolenbroek
1733319e7a6dSDavid van Moolenbroek PLAN *
c_user(char *** argvp,int isok)1734319e7a6dSDavid van Moolenbroek c_user(char ***argvp, int isok)
1735319e7a6dSDavid van Moolenbroek {
1736319e7a6dSDavid van Moolenbroek char *username = **argvp;
1737319e7a6dSDavid van Moolenbroek PLAN *new;
1738319e7a6dSDavid van Moolenbroek struct passwd *p;
1739319e7a6dSDavid van Moolenbroek uid_t uid;
1740319e7a6dSDavid van Moolenbroek
1741319e7a6dSDavid van Moolenbroek (*argvp)++;
1742319e7a6dSDavid van Moolenbroek ftsoptions &= ~FTS_NOSTAT;
1743319e7a6dSDavid van Moolenbroek
1744319e7a6dSDavid van Moolenbroek new = palloc(N_USER, f_user);
1745319e7a6dSDavid van Moolenbroek p = getpwnam(username);
1746319e7a6dSDavid van Moolenbroek if (p == NULL) {
1747319e7a6dSDavid van Moolenbroek if (atoi(username) == 0 && username[0] != '0' &&
1748319e7a6dSDavid van Moolenbroek strcmp(username, "+0") && strcmp(username, "-0"))
1749319e7a6dSDavid van Moolenbroek errx(1, "-user: %s: no such user", username);
1750319e7a6dSDavid van Moolenbroek uid = find_parsenum(new, "-user", username, NULL);
1751319e7a6dSDavid van Moolenbroek
1752319e7a6dSDavid van Moolenbroek } else {
1753319e7a6dSDavid van Moolenbroek new->flags = F_EQUAL;
1754319e7a6dSDavid van Moolenbroek uid = p->pw_uid;
1755319e7a6dSDavid van Moolenbroek }
1756319e7a6dSDavid van Moolenbroek
1757319e7a6dSDavid van Moolenbroek new->u_data = uid;
1758319e7a6dSDavid van Moolenbroek return (new);
1759319e7a6dSDavid van Moolenbroek }
1760319e7a6dSDavid van Moolenbroek
1761319e7a6dSDavid van Moolenbroek /*
1762319e7a6dSDavid van Moolenbroek * -xdev functions --
1763319e7a6dSDavid van Moolenbroek *
1764319e7a6dSDavid van Moolenbroek * Always true, causes find not to descend past directories that have a
1765319e7a6dSDavid van Moolenbroek * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
1766319e7a6dSDavid van Moolenbroek */
1767319e7a6dSDavid van Moolenbroek PLAN *
c_xdev(char *** argvp,int isok)1768319e7a6dSDavid van Moolenbroek c_xdev(char ***argvp, int isok)
1769319e7a6dSDavid van Moolenbroek {
1770319e7a6dSDavid van Moolenbroek ftsoptions |= FTS_XDEV;
1771319e7a6dSDavid van Moolenbroek
1772319e7a6dSDavid van Moolenbroek return (palloc(N_XDEV, f_always_true));
1773319e7a6dSDavid van Moolenbroek }
1774319e7a6dSDavid van Moolenbroek
1775319e7a6dSDavid van Moolenbroek /*
1776319e7a6dSDavid van Moolenbroek * ( expression ) functions --
1777319e7a6dSDavid van Moolenbroek *
1778319e7a6dSDavid van Moolenbroek * True if expression is true.
1779319e7a6dSDavid van Moolenbroek */
1780319e7a6dSDavid van Moolenbroek int
f_expr(PLAN * plan,FTSENT * entry)1781319e7a6dSDavid van Moolenbroek f_expr(PLAN *plan, FTSENT *entry)
1782319e7a6dSDavid van Moolenbroek {
1783319e7a6dSDavid van Moolenbroek PLAN *p;
1784319e7a6dSDavid van Moolenbroek int state;
1785319e7a6dSDavid van Moolenbroek
1786319e7a6dSDavid van Moolenbroek state = 0;
1787319e7a6dSDavid van Moolenbroek for (p = plan->p_data[0];
1788319e7a6dSDavid van Moolenbroek p && (state = (p->eval)(p, entry)); p = p->next);
1789319e7a6dSDavid van Moolenbroek return (state);
1790319e7a6dSDavid van Moolenbroek }
1791319e7a6dSDavid van Moolenbroek
1792319e7a6dSDavid van Moolenbroek /*
1793319e7a6dSDavid van Moolenbroek * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are
1794319e7a6dSDavid van Moolenbroek * eliminated during phase 2 of find_formplan() --- the '(' node is converted
1795319e7a6dSDavid van Moolenbroek * to a N_EXPR node containing the expression and the ')' node is discarded.
1796319e7a6dSDavid van Moolenbroek */
1797319e7a6dSDavid van Moolenbroek PLAN *
c_openparen(char *** argvp,int isok)1798319e7a6dSDavid van Moolenbroek c_openparen(char ***argvp, int isok)
1799319e7a6dSDavid van Moolenbroek {
1800319e7a6dSDavid van Moolenbroek
1801319e7a6dSDavid van Moolenbroek return (palloc(N_OPENPAREN, (int (*)(PLAN *, FTSENT *))-1));
1802319e7a6dSDavid van Moolenbroek }
1803319e7a6dSDavid van Moolenbroek
1804319e7a6dSDavid van Moolenbroek PLAN *
c_closeparen(char *** argvp,int isok)1805319e7a6dSDavid van Moolenbroek c_closeparen(char ***argvp, int isok)
1806319e7a6dSDavid van Moolenbroek {
1807319e7a6dSDavid van Moolenbroek
1808319e7a6dSDavid van Moolenbroek return (palloc(N_CLOSEPAREN, (int (*)(PLAN *, FTSENT *))-1));
1809319e7a6dSDavid van Moolenbroek }
1810319e7a6dSDavid van Moolenbroek
1811319e7a6dSDavid van Moolenbroek /*
1812319e7a6dSDavid van Moolenbroek * ! expression functions --
1813319e7a6dSDavid van Moolenbroek *
1814319e7a6dSDavid van Moolenbroek * Negation of a primary; the unary NOT operator.
1815319e7a6dSDavid van Moolenbroek */
1816319e7a6dSDavid van Moolenbroek int
f_not(PLAN * plan,FTSENT * entry)1817319e7a6dSDavid van Moolenbroek f_not(PLAN *plan, FTSENT *entry)
1818319e7a6dSDavid van Moolenbroek {
1819319e7a6dSDavid van Moolenbroek PLAN *p;
1820319e7a6dSDavid van Moolenbroek int state;
1821319e7a6dSDavid van Moolenbroek
1822319e7a6dSDavid van Moolenbroek state = 0;
1823319e7a6dSDavid van Moolenbroek for (p = plan->p_data[0];
1824319e7a6dSDavid van Moolenbroek p && (state = (p->eval)(p, entry)); p = p->next);
1825319e7a6dSDavid van Moolenbroek return (!state);
1826319e7a6dSDavid van Moolenbroek }
1827319e7a6dSDavid van Moolenbroek
1828319e7a6dSDavid van Moolenbroek PLAN *
c_not(char *** argvp,int isok)1829319e7a6dSDavid van Moolenbroek c_not(char ***argvp, int isok)
1830319e7a6dSDavid van Moolenbroek {
1831319e7a6dSDavid van Moolenbroek
1832319e7a6dSDavid van Moolenbroek return (palloc(N_NOT, f_not));
1833319e7a6dSDavid van Moolenbroek }
1834319e7a6dSDavid van Moolenbroek
1835319e7a6dSDavid van Moolenbroek /*
1836319e7a6dSDavid van Moolenbroek * expression -o expression functions --
1837319e7a6dSDavid van Moolenbroek *
1838319e7a6dSDavid van Moolenbroek * Alternation of primaries; the OR operator. The second expression is
1839319e7a6dSDavid van Moolenbroek * not evaluated if the first expression is true.
1840319e7a6dSDavid van Moolenbroek */
1841319e7a6dSDavid van Moolenbroek int
f_or(PLAN * plan,FTSENT * entry)1842319e7a6dSDavid van Moolenbroek f_or(PLAN *plan, FTSENT *entry)
1843319e7a6dSDavid van Moolenbroek {
1844319e7a6dSDavid van Moolenbroek PLAN *p;
1845319e7a6dSDavid van Moolenbroek int state;
1846319e7a6dSDavid van Moolenbroek
1847319e7a6dSDavid van Moolenbroek state = 0;
1848319e7a6dSDavid van Moolenbroek for (p = plan->p_data[0];
1849319e7a6dSDavid van Moolenbroek p && (state = (p->eval)(p, entry)); p = p->next);
1850319e7a6dSDavid van Moolenbroek
1851319e7a6dSDavid van Moolenbroek if (state)
1852319e7a6dSDavid van Moolenbroek return (1);
1853319e7a6dSDavid van Moolenbroek
1854319e7a6dSDavid van Moolenbroek for (p = plan->p_data[1];
1855319e7a6dSDavid van Moolenbroek p && (state = (p->eval)(p, entry)); p = p->next);
1856319e7a6dSDavid van Moolenbroek return (state);
1857319e7a6dSDavid van Moolenbroek }
1858319e7a6dSDavid van Moolenbroek
1859319e7a6dSDavid van Moolenbroek PLAN *
c_or(char *** argvp,int isok)1860319e7a6dSDavid van Moolenbroek c_or(char ***argvp, int isok)
1861319e7a6dSDavid van Moolenbroek {
1862319e7a6dSDavid van Moolenbroek
1863319e7a6dSDavid van Moolenbroek return (palloc(N_OR, f_or));
1864319e7a6dSDavid van Moolenbroek }
1865319e7a6dSDavid van Moolenbroek
1866319e7a6dSDavid van Moolenbroek PLAN *
c_null(char *** argvp,int isok)1867319e7a6dSDavid van Moolenbroek c_null(char ***argvp, int isok)
1868319e7a6dSDavid van Moolenbroek {
1869319e7a6dSDavid van Moolenbroek
1870319e7a6dSDavid van Moolenbroek return (NULL);
1871319e7a6dSDavid van Moolenbroek }
1872319e7a6dSDavid van Moolenbroek
1873319e7a6dSDavid van Moolenbroek
1874319e7a6dSDavid van Moolenbroek /*
1875319e7a6dSDavid van Moolenbroek * plan_cleanup --
1876319e7a6dSDavid van Moolenbroek * Check and see if the specified plan has any residual state,
1877319e7a6dSDavid van Moolenbroek * and if so, clean it up as appropriate.
1878319e7a6dSDavid van Moolenbroek *
1879319e7a6dSDavid van Moolenbroek * At the moment, only N_EXEC has state. Two kinds: 1)
1880319e7a6dSDavid van Moolenbroek * lists of files to feed to subprocesses 2) State on exit
1881319e7a6dSDavid van Moolenbroek * statusses of past subprocesses.
1882319e7a6dSDavid van Moolenbroek */
1883319e7a6dSDavid van Moolenbroek /* ARGSUSED1 */
1884319e7a6dSDavid van Moolenbroek int
plan_cleanup(PLAN * plan,void * arg)1885319e7a6dSDavid van Moolenbroek plan_cleanup(PLAN *plan, void *arg)
1886319e7a6dSDavid van Moolenbroek {
1887319e7a6dSDavid van Moolenbroek if (plan->type==N_EXEC && plan->ep_narg)
1888319e7a6dSDavid van Moolenbroek run_f_exec(plan);
1889319e7a6dSDavid van Moolenbroek
1890319e7a6dSDavid van Moolenbroek return plan->ep_rval; /* Passed save exit-status up chain */
1891319e7a6dSDavid van Moolenbroek }
1892319e7a6dSDavid van Moolenbroek
1893319e7a6dSDavid van Moolenbroek static PLAN *
palloc(enum ntype t,int (* f)(PLAN *,FTSENT *))1894319e7a6dSDavid van Moolenbroek palloc(enum ntype t, int (*f)(PLAN *, FTSENT *))
1895319e7a6dSDavid van Moolenbroek {
1896319e7a6dSDavid van Moolenbroek PLAN *new;
1897319e7a6dSDavid van Moolenbroek
1898319e7a6dSDavid van Moolenbroek if ((new = malloc(sizeof(PLAN))) == NULL)
1899319e7a6dSDavid van Moolenbroek err(1, NULL);
1900319e7a6dSDavid van Moolenbroek memset(new, 0, sizeof(PLAN));
1901319e7a6dSDavid van Moolenbroek new->type = t;
1902319e7a6dSDavid van Moolenbroek new->eval = f;
1903319e7a6dSDavid van Moolenbroek return (new);
1904319e7a6dSDavid van Moolenbroek }
1905