xref: /aosp_15_r20/external/toybox/toys/posix/find.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* find.c - Search directories for matching files.
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2014 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  *
5*cf5a6c84SAndroid Build Coastguard Worker  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.c
6*cf5a6c84SAndroid Build Coastguard Worker  *
7*cf5a6c84SAndroid Build Coastguard Worker  * Our "unspecified" behavior for no paths is to use "."
8*cf5a6c84SAndroid Build Coastguard Worker  * Parentheses can only stack 4096 deep
9*cf5a6c84SAndroid Build Coastguard Worker  * Not treating two {} as an error, but only using last
10*cf5a6c84SAndroid Build Coastguard Worker  * TODO: -context
11*cf5a6c84SAndroid Build Coastguard Worker 
12*cf5a6c84SAndroid Build Coastguard Worker USE_FIND(NEWTOY(find, "?^HL[-HL]", TOYFLAG_USR|TOYFLAG_BIN))
13*cf5a6c84SAndroid Build Coastguard Worker 
14*cf5a6c84SAndroid Build Coastguard Worker config FIND
15*cf5a6c84SAndroid Build Coastguard Worker   bool "find"
16*cf5a6c84SAndroid Build Coastguard Worker   default y
17*cf5a6c84SAndroid Build Coastguard Worker   help
18*cf5a6c84SAndroid Build Coastguard Worker     usage: find [-HL] [DIR...] [<options>]
19*cf5a6c84SAndroid Build Coastguard Worker 
20*cf5a6c84SAndroid Build Coastguard Worker     Search directories for matching files.
21*cf5a6c84SAndroid Build Coastguard Worker     Default: search ".", match all, -print matches.
22*cf5a6c84SAndroid Build Coastguard Worker 
23*cf5a6c84SAndroid Build Coastguard Worker     -H  Follow command line symlinks         -L  Follow all symlinks
24*cf5a6c84SAndroid Build Coastguard Worker 
25*cf5a6c84SAndroid Build Coastguard Worker     Match filters:
26*cf5a6c84SAndroid Build Coastguard Worker     -name  PATTERN   filename with wildcards   -iname      ignore case -name
27*cf5a6c84SAndroid Build Coastguard Worker     -path  PATTERN   path name with wildcards  -ipath      ignore case -path
28*cf5a6c84SAndroid Build Coastguard Worker     -user  UNAME     belongs to user UNAME     -nouser     user ID not known
29*cf5a6c84SAndroid Build Coastguard Worker     -group GROUP     belongs to group GROUP    -nogroup    group ID not known
30*cf5a6c84SAndroid Build Coastguard Worker     -perm  [-/]MODE  permissions (-=min /=any) -prune      ignore dir contents
31*cf5a6c84SAndroid Build Coastguard Worker     -size  N[c]      512 byte blocks (c=bytes) -xdev       only this filesystem
32*cf5a6c84SAndroid Build Coastguard Worker     -links N         hardlink count            -empty      empty files and dirs
33*cf5a6c84SAndroid Build Coastguard Worker     -atime N[u]      accessed N units ago      -true       always true
34*cf5a6c84SAndroid Build Coastguard Worker     -ctime N[u]      created N units ago       -false      always false
35*cf5a6c84SAndroid Build Coastguard Worker     -mtime N[u]      modified N units ago      -executable access(X_OK) perm+ACL
36*cf5a6c84SAndroid Build Coastguard Worker     -inum  N         inode number N            -readable   access(R_OK) perm+ACL
37*cf5a6c84SAndroid Build Coastguard Worker     -context PATTERN security context          -depth      contents before dir
38*cf5a6c84SAndroid Build Coastguard Worker     -samefile FILE   hardlink to FILE          -maxdepth N at most N dirs down
39*cf5a6c84SAndroid Build Coastguard Worker     -newer    FILE   newer mtime than FILE     -mindepth N at least N dirs down
40*cf5a6c84SAndroid Build Coastguard Worker     -newerXY  FILE   X=acm time > FILE's Y=acm time (Y=t: FILE is literal time)
41*cf5a6c84SAndroid Build Coastguard Worker     -type [bcdflps]  type is (block, char, dir, file, symlink, pipe, socket)
42*cf5a6c84SAndroid Build Coastguard Worker 
43*cf5a6c84SAndroid Build Coastguard Worker     Numbers N may be prefixed by - (less than) or + (greater than). Units for
44*cf5a6c84SAndroid Build Coastguard Worker     -[acm]time are d (days, default), h (hours), m (minutes), or s (seconds).
45*cf5a6c84SAndroid Build Coastguard Worker 
46*cf5a6c84SAndroid Build Coastguard Worker     Combine matches with:
47*cf5a6c84SAndroid Build Coastguard Worker     !, -a, -o, ( )    not, and, or, group expressions
48*cf5a6c84SAndroid Build Coastguard Worker 
49*cf5a6c84SAndroid Build Coastguard Worker     Actions:
50*cf5a6c84SAndroid Build Coastguard Worker     -print  Print match with newline  -print0        Print match with null
51*cf5a6c84SAndroid Build Coastguard Worker     -exec   Run command with path     -execdir       Run command in file's dir
52*cf5a6c84SAndroid Build Coastguard Worker     -ok     Ask before exec           -okdir         Ask before execdir
53*cf5a6c84SAndroid Build Coastguard Worker     -delete Remove matching file/dir  -printf FORMAT Print using format string
54*cf5a6c84SAndroid Build Coastguard Worker     -quit   Exit immediately
55*cf5a6c84SAndroid Build Coastguard Worker 
56*cf5a6c84SAndroid Build Coastguard Worker     Commands substitute "{}" with matched file. End with ";" to run each file,
57*cf5a6c84SAndroid Build Coastguard Worker     or "+" (next argument after "{}") to collect and run with multiple files.
58*cf5a6c84SAndroid Build Coastguard Worker 
59*cf5a6c84SAndroid Build Coastguard Worker     -printf FORMAT characters are \ escapes and:
60*cf5a6c84SAndroid Build Coastguard Worker     %b  512 byte blocks used
61*cf5a6c84SAndroid Build Coastguard Worker     %f  basename            %g  textual gid          %G  numeric gid
62*cf5a6c84SAndroid Build Coastguard Worker     %i  decimal inode       %l  target of symlink    %m  octal mode
63*cf5a6c84SAndroid Build Coastguard Worker     %M  ls format type/mode %p  path to file         %P  path to file minus DIR
64*cf5a6c84SAndroid Build Coastguard Worker     %s  size in bytes       %T@ mod time as unixtime
65*cf5a6c84SAndroid Build Coastguard Worker     %u  username            %U  numeric uid          %Z  security context
66*cf5a6c84SAndroid Build Coastguard Worker */
67*cf5a6c84SAndroid Build Coastguard Worker 
68*cf5a6c84SAndroid Build Coastguard Worker #define FOR_find
69*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
70*cf5a6c84SAndroid Build Coastguard Worker 
71*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
72*cf5a6c84SAndroid Build Coastguard Worker   char **filter;
73*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *argdata;
74*cf5a6c84SAndroid Build Coastguard Worker   int topdir, xdev, depth;
75*cf5a6c84SAndroid Build Coastguard Worker   time_t now;
76*cf5a6c84SAndroid Build Coastguard Worker   long max_bytes;
77*cf5a6c84SAndroid Build Coastguard Worker   char *start;
78*cf5a6c84SAndroid Build Coastguard Worker )
79*cf5a6c84SAndroid Build Coastguard Worker 
80*cf5a6c84SAndroid Build Coastguard Worker struct execdir_data {
81*cf5a6c84SAndroid Build Coastguard Worker   struct execdir_data *next;
82*cf5a6c84SAndroid Build Coastguard Worker 
83*cf5a6c84SAndroid Build Coastguard Worker   int namecount;
84*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *names;
85*cf5a6c84SAndroid Build Coastguard Worker };
86*cf5a6c84SAndroid Build Coastguard Worker 
87*cf5a6c84SAndroid Build Coastguard Worker // None of this can go in TT because you can have more than one -exec
88*cf5a6c84SAndroid Build Coastguard Worker struct exec_range {
89*cf5a6c84SAndroid Build Coastguard Worker   char *next, *prev;  // layout compatible with struct double_list
90*cf5a6c84SAndroid Build Coastguard Worker 
91*cf5a6c84SAndroid Build Coastguard Worker   int dir, plus, arglen, argsize, curly;
92*cf5a6c84SAndroid Build Coastguard Worker   char **argstart;
93*cf5a6c84SAndroid Build Coastguard Worker   struct execdir_data exec, *execdir;
94*cf5a6c84SAndroid Build Coastguard Worker };
95*cf5a6c84SAndroid Build Coastguard Worker 
96*cf5a6c84SAndroid Build Coastguard Worker // Perform pending -exec (if any)
flush_exec(struct dirtree * new,struct exec_range * aa)97*cf5a6c84SAndroid Build Coastguard Worker static int flush_exec(struct dirtree *new, struct exec_range *aa)
98*cf5a6c84SAndroid Build Coastguard Worker {
99*cf5a6c84SAndroid Build Coastguard Worker   struct execdir_data *bb = aa->execdir ? aa->execdir : &aa->exec;
100*cf5a6c84SAndroid Build Coastguard Worker   char **newargs;
101*cf5a6c84SAndroid Build Coastguard Worker   int rc, revert = 0;
102*cf5a6c84SAndroid Build Coastguard Worker 
103*cf5a6c84SAndroid Build Coastguard Worker   if (!bb->namecount) return 0;
104*cf5a6c84SAndroid Build Coastguard Worker 
105*cf5a6c84SAndroid Build Coastguard Worker   dlist_terminate(bb->names);
106*cf5a6c84SAndroid Build Coastguard Worker 
107*cf5a6c84SAndroid Build Coastguard Worker   // switch to directory for -execdir, or back to top if we have an -execdir
108*cf5a6c84SAndroid Build Coastguard Worker   // _and_ a normal -exec, or are at top of tree in -execdir
109*cf5a6c84SAndroid Build Coastguard Worker   if (TT.topdir != -1) {
110*cf5a6c84SAndroid Build Coastguard Worker     if (aa->dir && new && new->parent) {
111*cf5a6c84SAndroid Build Coastguard Worker       revert++;
112*cf5a6c84SAndroid Build Coastguard Worker       rc = fchdir(new->parent->dirfd);
113*cf5a6c84SAndroid Build Coastguard Worker     } else rc = fchdir(TT.topdir);
114*cf5a6c84SAndroid Build Coastguard Worker     if (rc) {
115*cf5a6c84SAndroid Build Coastguard Worker       perror_msg_raw(revert ? new->name : ".");
116*cf5a6c84SAndroid Build Coastguard Worker 
117*cf5a6c84SAndroid Build Coastguard Worker       return rc;
118*cf5a6c84SAndroid Build Coastguard Worker     }
119*cf5a6c84SAndroid Build Coastguard Worker   }
120*cf5a6c84SAndroid Build Coastguard Worker 
121*cf5a6c84SAndroid Build Coastguard Worker   // execdir: accumulated execs in this directory's children.
122*cf5a6c84SAndroid Build Coastguard Worker   newargs = xmalloc(sizeof(char *)*(aa->arglen+bb->namecount+1));
123*cf5a6c84SAndroid Build Coastguard Worker   if (aa->curly < 0) {
124*cf5a6c84SAndroid Build Coastguard Worker     memcpy(newargs, aa->argstart, sizeof(char *)*aa->arglen);
125*cf5a6c84SAndroid Build Coastguard Worker     newargs[aa->arglen] = 0;
126*cf5a6c84SAndroid Build Coastguard Worker   } else {
127*cf5a6c84SAndroid Build Coastguard Worker     int pos = aa->curly, rest = aa->arglen - aa->curly;
128*cf5a6c84SAndroid Build Coastguard Worker     struct double_list *dl;
129*cf5a6c84SAndroid Build Coastguard Worker 
130*cf5a6c84SAndroid Build Coastguard Worker     // Collate argument list
131*cf5a6c84SAndroid Build Coastguard Worker     memcpy(newargs, aa->argstart, sizeof(char *)*pos);
132*cf5a6c84SAndroid Build Coastguard Worker     for (dl = bb->names; dl; dl = dl->next) newargs[pos++] = dl->data;
133*cf5a6c84SAndroid Build Coastguard Worker     rest = aa->arglen - aa->curly - 1;
134*cf5a6c84SAndroid Build Coastguard Worker     memcpy(newargs+pos, aa->argstart+aa->curly+1, sizeof(char *)*rest);
135*cf5a6c84SAndroid Build Coastguard Worker     newargs[pos+rest] = 0;
136*cf5a6c84SAndroid Build Coastguard Worker   }
137*cf5a6c84SAndroid Build Coastguard Worker 
138*cf5a6c84SAndroid Build Coastguard Worker   rc = xrun(newargs);
139*cf5a6c84SAndroid Build Coastguard Worker 
140*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse(bb->names, llist_free_double);
141*cf5a6c84SAndroid Build Coastguard Worker   bb->names = 0;
142*cf5a6c84SAndroid Build Coastguard Worker   bb->namecount = 0;
143*cf5a6c84SAndroid Build Coastguard Worker 
144*cf5a6c84SAndroid Build Coastguard Worker   if (revert) revert = fchdir(TT.topdir);
145*cf5a6c84SAndroid Build Coastguard Worker 
146*cf5a6c84SAndroid Build Coastguard Worker   return rc;
147*cf5a6c84SAndroid Build Coastguard Worker }
148*cf5a6c84SAndroid Build Coastguard Worker 
149*cf5a6c84SAndroid Build Coastguard Worker // Return numeric value with explicit sign
compare_numsign(long val,long units,char * str)150*cf5a6c84SAndroid Build Coastguard Worker static int compare_numsign(long val, long units, char *str)
151*cf5a6c84SAndroid Build Coastguard Worker {
152*cf5a6c84SAndroid Build Coastguard Worker   char sign = 0;
153*cf5a6c84SAndroid Build Coastguard Worker   long myval;
154*cf5a6c84SAndroid Build Coastguard Worker 
155*cf5a6c84SAndroid Build Coastguard Worker   if (*str == '+' || *str == '-') sign = *(str++);
156*cf5a6c84SAndroid Build Coastguard Worker   else if (!isdigit(*str)) error_exit("%s not [+-]N", str);
157*cf5a6c84SAndroid Build Coastguard Worker   myval = atolx(str);
158*cf5a6c84SAndroid Build Coastguard Worker   if (units && isdigit(str[strlen(str)-1])) myval *= units;
159*cf5a6c84SAndroid Build Coastguard Worker 
160*cf5a6c84SAndroid Build Coastguard Worker   if (sign == '+') return val > myval;
161*cf5a6c84SAndroid Build Coastguard Worker   if (sign == '-') return val < myval;
162*cf5a6c84SAndroid Build Coastguard Worker   return val == myval;
163*cf5a6c84SAndroid Build Coastguard Worker }
164*cf5a6c84SAndroid Build Coastguard Worker 
do_print(struct dirtree * new,char c)165*cf5a6c84SAndroid Build Coastguard Worker static void do_print(struct dirtree *new, char c)
166*cf5a6c84SAndroid Build Coastguard Worker {
167*cf5a6c84SAndroid Build Coastguard Worker   char *s=dirtree_path(new, 0);
168*cf5a6c84SAndroid Build Coastguard Worker 
169*cf5a6c84SAndroid Build Coastguard Worker   xprintf("%s%c", s, c);
170*cf5a6c84SAndroid Build Coastguard Worker   free(s);
171*cf5a6c84SAndroid Build Coastguard Worker }
172*cf5a6c84SAndroid Build Coastguard Worker 
173*cf5a6c84SAndroid Build Coastguard Worker // Descend or ascend -execdir + directory level
execdir(struct dirtree * new,int flush)174*cf5a6c84SAndroid Build Coastguard Worker static void execdir(struct dirtree *new, int flush)
175*cf5a6c84SAndroid Build Coastguard Worker {
176*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *dl;
177*cf5a6c84SAndroid Build Coastguard Worker   struct exec_range *aa;
178*cf5a6c84SAndroid Build Coastguard Worker   struct execdir_data *bb;
179*cf5a6c84SAndroid Build Coastguard Worker 
180*cf5a6c84SAndroid Build Coastguard Worker   if (new && TT.topdir == -1) return;
181*cf5a6c84SAndroid Build Coastguard Worker 
182*cf5a6c84SAndroid Build Coastguard Worker   for (dl = TT.argdata; dl; dl = dl->next) {
183*cf5a6c84SAndroid Build Coastguard Worker     if (dl->prev != (void *)1) continue;
184*cf5a6c84SAndroid Build Coastguard Worker     aa = (void *)dl;
185*cf5a6c84SAndroid Build Coastguard Worker     if (!aa->plus || (new && !aa->dir)) continue;
186*cf5a6c84SAndroid Build Coastguard Worker 
187*cf5a6c84SAndroid Build Coastguard Worker     if (flush) {
188*cf5a6c84SAndroid Build Coastguard Worker 
189*cf5a6c84SAndroid Build Coastguard Worker       // Flush pending "-execdir +" instances for this dir
190*cf5a6c84SAndroid Build Coastguard Worker       // or flush everything for -exec at top
191*cf5a6c84SAndroid Build Coastguard Worker       toys.exitval |= flush_exec(new, aa);
192*cf5a6c84SAndroid Build Coastguard Worker 
193*cf5a6c84SAndroid Build Coastguard Worker       // pop per-directory struct
194*cf5a6c84SAndroid Build Coastguard Worker       if ((bb = aa->execdir)) {
195*cf5a6c84SAndroid Build Coastguard Worker         aa->execdir = bb->next;
196*cf5a6c84SAndroid Build Coastguard Worker         free(bb);
197*cf5a6c84SAndroid Build Coastguard Worker       }
198*cf5a6c84SAndroid Build Coastguard Worker     } else if (aa->dir) {
199*cf5a6c84SAndroid Build Coastguard Worker 
200*cf5a6c84SAndroid Build Coastguard Worker       // Push new per-directory struct for -execdir/okdir + codepath. (Can't
201*cf5a6c84SAndroid Build Coastguard Worker       // use new->extra because command line may have multiple -execdir)
202*cf5a6c84SAndroid Build Coastguard Worker       bb = xzalloc(sizeof(struct execdir_data));
203*cf5a6c84SAndroid Build Coastguard Worker       bb->next = aa->execdir;
204*cf5a6c84SAndroid Build Coastguard Worker       aa->execdir = bb;
205*cf5a6c84SAndroid Build Coastguard Worker     }
206*cf5a6c84SAndroid Build Coastguard Worker   }
207*cf5a6c84SAndroid Build Coastguard Worker }
208*cf5a6c84SAndroid Build Coastguard Worker 
209*cf5a6c84SAndroid Build Coastguard Worker // Call this with 0 for first pass argument parsing and syntax checking (which
210*cf5a6c84SAndroid Build Coastguard Worker // populates argdata). Later commands traverse argdata (in order) when they
211*cf5a6c84SAndroid Build Coastguard Worker // need "do once" results.
do_find(struct dirtree * new)212*cf5a6c84SAndroid Build Coastguard Worker static int do_find(struct dirtree *new)
213*cf5a6c84SAndroid Build Coastguard Worker {
214*cf5a6c84SAndroid Build Coastguard Worker   int pcount = 0, print = 0, not = 0, active = !!new, test = active, recurse;
215*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *argdata = TT.argdata;
216*cf5a6c84SAndroid Build Coastguard Worker   char *s, **ss, *arg;
217*cf5a6c84SAndroid Build Coastguard Worker 
218*cf5a6c84SAndroid Build Coastguard Worker   recurse = DIRTREE_STATLESS|DIRTREE_COMEAGAIN|DIRTREE_SYMFOLLOW*FLAG(L);
219*cf5a6c84SAndroid Build Coastguard Worker 
220*cf5a6c84SAndroid Build Coastguard Worker   // skip . and .. below topdir, handle -xdev and -depth
221*cf5a6c84SAndroid Build Coastguard Worker   if (new) {
222*cf5a6c84SAndroid Build Coastguard Worker     // Handle stat failures first.
223*cf5a6c84SAndroid Build Coastguard Worker     if (new->again&DIRTREE_STATLESS) {
224*cf5a6c84SAndroid Build Coastguard Worker       if (!new->parent || errno != ENOENT) {
225*cf5a6c84SAndroid Build Coastguard Worker         perror_msg("'%s'", s = dirtree_path(new, 0));
226*cf5a6c84SAndroid Build Coastguard Worker         free(s);
227*cf5a6c84SAndroid Build Coastguard Worker       }
228*cf5a6c84SAndroid Build Coastguard Worker       return 0;
229*cf5a6c84SAndroid Build Coastguard Worker     }
230*cf5a6c84SAndroid Build Coastguard Worker     if (new->parent) {
231*cf5a6c84SAndroid Build Coastguard Worker       if (!dirtree_notdotdot(new)) return 0;
232*cf5a6c84SAndroid Build Coastguard Worker       if (TT.xdev && new->st.st_dev != new->parent->st.st_dev) recurse = 0;
233*cf5a6c84SAndroid Build Coastguard Worker     } else TT.start = new->name;
234*cf5a6c84SAndroid Build Coastguard Worker 
235*cf5a6c84SAndroid Build Coastguard Worker     if (S_ISDIR(new->st.st_mode)) {
236*cf5a6c84SAndroid Build Coastguard Worker       // Descending into new directory
237*cf5a6c84SAndroid Build Coastguard Worker       if (!(new->again&DIRTREE_COMEAGAIN)) {
238*cf5a6c84SAndroid Build Coastguard Worker         struct dirtree *n;
239*cf5a6c84SAndroid Build Coastguard Worker 
240*cf5a6c84SAndroid Build Coastguard Worker         for (n = new->parent; n; n = n->parent) {
241*cf5a6c84SAndroid Build Coastguard Worker           if (same_file(&n->st, &new->st)) {
242*cf5a6c84SAndroid Build Coastguard Worker             error_msg("'%s': loop detected", s = dirtree_path(new, 0));
243*cf5a6c84SAndroid Build Coastguard Worker             free(s);
244*cf5a6c84SAndroid Build Coastguard Worker 
245*cf5a6c84SAndroid Build Coastguard Worker             return 0;
246*cf5a6c84SAndroid Build Coastguard Worker           }
247*cf5a6c84SAndroid Build Coastguard Worker         }
248*cf5a6c84SAndroid Build Coastguard Worker 
249*cf5a6c84SAndroid Build Coastguard Worker         if (TT.depth) {
250*cf5a6c84SAndroid Build Coastguard Worker           execdir(new, 0);
251*cf5a6c84SAndroid Build Coastguard Worker 
252*cf5a6c84SAndroid Build Coastguard Worker           return recurse;
253*cf5a6c84SAndroid Build Coastguard Worker         }
254*cf5a6c84SAndroid Build Coastguard Worker       // Done with directory (COMEAGAIN call)
255*cf5a6c84SAndroid Build Coastguard Worker       } else {
256*cf5a6c84SAndroid Build Coastguard Worker         execdir(new, 1);
257*cf5a6c84SAndroid Build Coastguard Worker         recurse = 0;
258*cf5a6c84SAndroid Build Coastguard Worker         if (!TT.depth) return 0;
259*cf5a6c84SAndroid Build Coastguard Worker       }
260*cf5a6c84SAndroid Build Coastguard Worker     }
261*cf5a6c84SAndroid Build Coastguard Worker   }
262*cf5a6c84SAndroid Build Coastguard Worker 
263*cf5a6c84SAndroid Build Coastguard Worker   // pcount: parentheses stack depth (using toybuf bytes, 4096 max depth)
264*cf5a6c84SAndroid Build Coastguard Worker   // test: result of most recent test
265*cf5a6c84SAndroid Build Coastguard Worker   // active: if 0 don't perform tests
266*cf5a6c84SAndroid Build Coastguard Worker   // not: a pending ! applies to this test (only set if performing tests)
267*cf5a6c84SAndroid Build Coastguard Worker   // print: saw one of print/ok/exec, no need for default -print
268*cf5a6c84SAndroid Build Coastguard Worker 
269*cf5a6c84SAndroid Build Coastguard Worker   if (TT.filter) for (ss = TT.filter; (s = *ss); ss++) {
270*cf5a6c84SAndroid Build Coastguard Worker     int check = active && test;
271*cf5a6c84SAndroid Build Coastguard Worker 
272*cf5a6c84SAndroid Build Coastguard Worker     // if (!new) perform one-time setup, if (check) perform test
273*cf5a6c84SAndroid Build Coastguard Worker 
274*cf5a6c84SAndroid Build Coastguard Worker     // handle ! ( ) using toybuf as a stack
275*cf5a6c84SAndroid Build Coastguard Worker     if (*s != '-') {
276*cf5a6c84SAndroid Build Coastguard Worker       if (s[1]) goto error;
277*cf5a6c84SAndroid Build Coastguard Worker 
278*cf5a6c84SAndroid Build Coastguard Worker       if (*s == '!') {
279*cf5a6c84SAndroid Build Coastguard Worker         // Don't invert if we're not making a decision
280*cf5a6c84SAndroid Build Coastguard Worker         if (check) not = !not;
281*cf5a6c84SAndroid Build Coastguard Worker 
282*cf5a6c84SAndroid Build Coastguard Worker       // Save old "not" and "active" on toybuf stack.
283*cf5a6c84SAndroid Build Coastguard Worker       // Deactivate this parenthetical if !test
284*cf5a6c84SAndroid Build Coastguard Worker       // Note: test value should never change while !active
285*cf5a6c84SAndroid Build Coastguard Worker       } else if (*s == '(') {
286*cf5a6c84SAndroid Build Coastguard Worker         if (pcount == sizeof(toybuf)) goto error;
287*cf5a6c84SAndroid Build Coastguard Worker         toybuf[pcount++] = not+(active<<1);
288*cf5a6c84SAndroid Build Coastguard Worker         if (!check) active = 0;
289*cf5a6c84SAndroid Build Coastguard Worker         not = 0;
290*cf5a6c84SAndroid Build Coastguard Worker 
291*cf5a6c84SAndroid Build Coastguard Worker       // Pop status, apply deferred not to test
292*cf5a6c84SAndroid Build Coastguard Worker       } else if (*s == ')') {
293*cf5a6c84SAndroid Build Coastguard Worker         if (--pcount < 0) goto error;
294*cf5a6c84SAndroid Build Coastguard Worker         // Pop active state, apply deferred not (which was only set if checking)
295*cf5a6c84SAndroid Build Coastguard Worker         active = (toybuf[pcount]>>1)&1;
296*cf5a6c84SAndroid Build Coastguard Worker         if (active && (toybuf[pcount]&1)) test = !test;
297*cf5a6c84SAndroid Build Coastguard Worker         not = 0;
298*cf5a6c84SAndroid Build Coastguard Worker       } else goto error;
299*cf5a6c84SAndroid Build Coastguard Worker 
300*cf5a6c84SAndroid Build Coastguard Worker       continue;
301*cf5a6c84SAndroid Build Coastguard Worker     } else s++;
302*cf5a6c84SAndroid Build Coastguard Worker 
303*cf5a6c84SAndroid Build Coastguard Worker     if (!strcmp(s, "xdev")) TT.xdev = 1;
304*cf5a6c84SAndroid Build Coastguard Worker     else if (!strcmp(s, "delete")) {
305*cf5a6c84SAndroid Build Coastguard Worker       // Delete forces depth first
306*cf5a6c84SAndroid Build Coastguard Worker       TT.depth = 1;
307*cf5a6c84SAndroid Build Coastguard Worker       if (new && check)
308*cf5a6c84SAndroid Build Coastguard Worker         test = !unlinkat(dirtree_parentfd(new), new->name,
309*cf5a6c84SAndroid Build Coastguard Worker           S_ISDIR(new->st.st_mode) ? AT_REMOVEDIR : 0);
310*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "depth") || !strcmp(s, "d")) TT.depth = 1;
311*cf5a6c84SAndroid Build Coastguard Worker     else if (!strcmp(s, "o") || !strcmp(s, "or")) {
312*cf5a6c84SAndroid Build Coastguard Worker       if (not) goto error;
313*cf5a6c84SAndroid Build Coastguard Worker       if (active) {
314*cf5a6c84SAndroid Build Coastguard Worker         if (!test) test = 1;
315*cf5a6c84SAndroid Build Coastguard Worker         else active = 0;     // decision has been made until next ")"
316*cf5a6c84SAndroid Build Coastguard Worker       }
317*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "not")) {
318*cf5a6c84SAndroid Build Coastguard Worker       if (check) not = !not;
319*cf5a6c84SAndroid Build Coastguard Worker       continue;
320*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "true")) {
321*cf5a6c84SAndroid Build Coastguard Worker       if (check) test = 1;
322*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "false")) {
323*cf5a6c84SAndroid Build Coastguard Worker       if (check) test = 0;
324*cf5a6c84SAndroid Build Coastguard Worker 
325*cf5a6c84SAndroid Build Coastguard Worker     // Mostly ignore NOP argument
326*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "a") || !strcmp(s, "and") || !strcmp(s, "noleaf")) {
327*cf5a6c84SAndroid Build Coastguard Worker       if (not) goto error;
328*cf5a6c84SAndroid Build Coastguard Worker 
329*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "print") || !strcmp("print0", s)) {
330*cf5a6c84SAndroid Build Coastguard Worker       print++;
331*cf5a6c84SAndroid Build Coastguard Worker       if (check) do_print(new, s[5] ? 0 : '\n');
332*cf5a6c84SAndroid Build Coastguard Worker 
333*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "empty")) {
334*cf5a6c84SAndroid Build Coastguard Worker       if (check) {
335*cf5a6c84SAndroid Build Coastguard Worker         // Alas neither st_size nor st_blocks reliably show an empty directory
336*cf5a6c84SAndroid Build Coastguard Worker         if (S_ISDIR(new->st.st_mode)) {
337*cf5a6c84SAndroid Build Coastguard Worker           int fd = openat(dirtree_parentfd(new), new->name, O_RDONLY);
338*cf5a6c84SAndroid Build Coastguard Worker           DIR *dfd = fdopendir(fd);
339*cf5a6c84SAndroid Build Coastguard Worker           struct dirent *de = (void *)1;
340*cf5a6c84SAndroid Build Coastguard Worker           if (dfd) {
341*cf5a6c84SAndroid Build Coastguard Worker             while ((de = readdir(dfd)) && isdotdot(de->d_name));
342*cf5a6c84SAndroid Build Coastguard Worker             closedir(dfd);
343*cf5a6c84SAndroid Build Coastguard Worker           }
344*cf5a6c84SAndroid Build Coastguard Worker           if (de) test = 0;
345*cf5a6c84SAndroid Build Coastguard Worker         } else if (S_ISREG(new->st.st_mode)) {
346*cf5a6c84SAndroid Build Coastguard Worker           if (new->st.st_size) test = 0;
347*cf5a6c84SAndroid Build Coastguard Worker         } else test = 0;
348*cf5a6c84SAndroid Build Coastguard Worker       }
349*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "nouser")) {
350*cf5a6c84SAndroid Build Coastguard Worker       if (check && bufgetpwuid(new->st.st_uid)) test = 0;
351*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "nogroup")) {
352*cf5a6c84SAndroid Build Coastguard Worker       if (check && bufgetgrgid(new->st.st_gid)) test = 0;
353*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "prune")) {
354*cf5a6c84SAndroid Build Coastguard Worker       if (check && S_ISDIR(new->st.st_mode) && !TT.depth) recurse = 0;
355*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "executable") || !strcmp(s, "readable")) {
356*cf5a6c84SAndroid Build Coastguard Worker       if (check && faccessat(dirtree_parentfd(new), new->name,
357*cf5a6c84SAndroid Build Coastguard Worker           *s=='r' ? R_OK : X_OK, 0)) test = 0;
358*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strcmp(s, "quit")) {
359*cf5a6c84SAndroid Build Coastguard Worker       if (check) {
360*cf5a6c84SAndroid Build Coastguard Worker         execdir(0, 1);
361*cf5a6c84SAndroid Build Coastguard Worker         xexit();
362*cf5a6c84SAndroid Build Coastguard Worker       }
363*cf5a6c84SAndroid Build Coastguard Worker 
364*cf5a6c84SAndroid Build Coastguard Worker     // Remaining filters take an argument
365*cf5a6c84SAndroid Build Coastguard Worker     } else {
366*cf5a6c84SAndroid Build Coastguard Worker       arg = *++ss;
367*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(s, "name") || !strcmp(s, "iname")
368*cf5a6c84SAndroid Build Coastguard Worker         || !strcmp(s, "wholename") || !strcmp(s, "iwholename")
369*cf5a6c84SAndroid Build Coastguard Worker         || !strcmp(s, "path") || !strcmp(s, "ipath")
370*cf5a6c84SAndroid Build Coastguard Worker         || !strcmp(s, "lname") || !strcmp(s, "ilname"))
371*cf5a6c84SAndroid Build Coastguard Worker       {
372*cf5a6c84SAndroid Build Coastguard Worker         int i = (*s == 'i'), is_path = (s[i] != 'n');
373*cf5a6c84SAndroid Build Coastguard Worker         char *path = 0, *name = new ? new->name : arg;
374*cf5a6c84SAndroid Build Coastguard Worker 
375*cf5a6c84SAndroid Build Coastguard Worker         // Handle path expansion and case flattening
376*cf5a6c84SAndroid Build Coastguard Worker         if (new && s[i] == 'l')
377*cf5a6c84SAndroid Build Coastguard Worker           name = path = xreadlinkat(dirtree_parentfd(new), new->name);
378*cf5a6c84SAndroid Build Coastguard Worker         else if (new && is_path) name = path = dirtree_path(new, 0);
379*cf5a6c84SAndroid Build Coastguard Worker         if (i) {
380*cf5a6c84SAndroid Build Coastguard Worker           if ((check || !new) && name) name = strlower(name);
381*cf5a6c84SAndroid Build Coastguard Worker           if (!new) dlist_add(&TT.argdata, name);
382*cf5a6c84SAndroid Build Coastguard Worker           else arg = ((struct double_list *)llist_pop(&argdata))->data;
383*cf5a6c84SAndroid Build Coastguard Worker         }
384*cf5a6c84SAndroid Build Coastguard Worker 
385*cf5a6c84SAndroid Build Coastguard Worker         if (check) {
386*cf5a6c84SAndroid Build Coastguard Worker           test = !fnmatch(arg, path ? name : basename(name),
387*cf5a6c84SAndroid Build Coastguard Worker             FNM_PATHNAME*(!is_path));
388*cf5a6c84SAndroid Build Coastguard Worker           if (i) free(name);
389*cf5a6c84SAndroid Build Coastguard Worker         }
390*cf5a6c84SAndroid Build Coastguard Worker         free(path);
391*cf5a6c84SAndroid Build Coastguard Worker       } else if (!CFG_TOYBOX_LSM_NONE && !strcmp(s, "context")) {
392*cf5a6c84SAndroid Build Coastguard Worker         if (check) {
393*cf5a6c84SAndroid Build Coastguard Worker           char *path = dirtree_path(new, 0), *context;
394*cf5a6c84SAndroid Build Coastguard Worker 
395*cf5a6c84SAndroid Build Coastguard Worker           if (lsm_get_context(path, &context) != -1) {
396*cf5a6c84SAndroid Build Coastguard Worker             test = !fnmatch(arg, context, 0);
397*cf5a6c84SAndroid Build Coastguard Worker             free(context);
398*cf5a6c84SAndroid Build Coastguard Worker           } else test = 0;
399*cf5a6c84SAndroid Build Coastguard Worker           free(path);
400*cf5a6c84SAndroid Build Coastguard Worker         }
401*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "perm")) {
402*cf5a6c84SAndroid Build Coastguard Worker         if (check) {
403*cf5a6c84SAndroid Build Coastguard Worker           int match_min = *arg == '-', match_any = *arg == '/';
404*cf5a6c84SAndroid Build Coastguard Worker           mode_t m1 = string_to_mode(arg+(match_min || match_any), 0),
405*cf5a6c84SAndroid Build Coastguard Worker                  m2 = new->st.st_mode & 07777;
406*cf5a6c84SAndroid Build Coastguard Worker 
407*cf5a6c84SAndroid Build Coastguard Worker           if (match_min || match_any) m2 &= m1;
408*cf5a6c84SAndroid Build Coastguard Worker           test = match_any ? !m1 || m2 : m1 == m2;
409*cf5a6c84SAndroid Build Coastguard Worker         }
410*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "type")) {
411*cf5a6c84SAndroid Build Coastguard Worker         if (check) {
412*cf5a6c84SAndroid Build Coastguard Worker           int types[] = {S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFIFO,
413*cf5a6c84SAndroid Build Coastguard Worker                          S_IFREG, S_IFSOCK}, i;
414*cf5a6c84SAndroid Build Coastguard Worker 
415*cf5a6c84SAndroid Build Coastguard Worker           for (; *arg; arg++) {
416*cf5a6c84SAndroid Build Coastguard Worker             if (*arg == ',') continue;
417*cf5a6c84SAndroid Build Coastguard Worker             i = stridx("bcdlpfs", *arg);
418*cf5a6c84SAndroid Build Coastguard Worker             if (i<0) error_exit("bad -type '%c'", *arg);
419*cf5a6c84SAndroid Build Coastguard Worker             if ((new->st.st_mode & S_IFMT) == types[i]) break;
420*cf5a6c84SAndroid Build Coastguard Worker           }
421*cf5a6c84SAndroid Build Coastguard Worker           test = *arg;
422*cf5a6c84SAndroid Build Coastguard Worker         }
423*cf5a6c84SAndroid Build Coastguard Worker 
424*cf5a6c84SAndroid Build Coastguard Worker       } else if (strchr("acm", *s)
425*cf5a6c84SAndroid Build Coastguard Worker         && (!strcmp(s+1, "time") || !strcmp(s+1, "min")))
426*cf5a6c84SAndroid Build Coastguard Worker       {
427*cf5a6c84SAndroid Build Coastguard Worker         if (check) {
428*cf5a6c84SAndroid Build Coastguard Worker           time_t thyme = (int []){new->st.st_atime, new->st.st_ctime,
429*cf5a6c84SAndroid Build Coastguard Worker                                   new->st.st_mtime}[stridx("acm", *s)];
430*cf5a6c84SAndroid Build Coastguard Worker           int len = strlen(arg), uu, units = (s[1]=='m') ? 60 : 86400;
431*cf5a6c84SAndroid Build Coastguard Worker 
432*cf5a6c84SAndroid Build Coastguard Worker           if (len && -1!=(uu = stridx("dhms",tolower(arg[len-1])))) {
433*cf5a6c84SAndroid Build Coastguard Worker             arg = xstrdup(arg);
434*cf5a6c84SAndroid Build Coastguard Worker             arg[--len] = 0;
435*cf5a6c84SAndroid Build Coastguard Worker             units = (int []){86400, 3600, 60, 1}[uu];
436*cf5a6c84SAndroid Build Coastguard Worker           }
437*cf5a6c84SAndroid Build Coastguard Worker           test = compare_numsign(TT.now - thyme, units, arg);
438*cf5a6c84SAndroid Build Coastguard Worker           if (*ss != arg) free(arg);
439*cf5a6c84SAndroid Build Coastguard Worker         }
440*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "size")) {
441*cf5a6c84SAndroid Build Coastguard Worker         if (check) test = compare_numsign(new->st.st_size, -512, arg) &&
442*cf5a6c84SAndroid Build Coastguard Worker                           S_ISREG(new->st.st_mode);
443*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "links")) {
444*cf5a6c84SAndroid Build Coastguard Worker         if (check) test = compare_numsign(new->st.st_nlink, 0, arg);
445*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "inum")) {
446*cf5a6c84SAndroid Build Coastguard Worker         if (check) test = compare_numsign(new->st.st_ino, 0, arg);
447*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "mindepth") || !strcmp(s, "maxdepth")) {
448*cf5a6c84SAndroid Build Coastguard Worker         if (check) {
449*cf5a6c84SAndroid Build Coastguard Worker           struct dirtree *dt = new;
450*cf5a6c84SAndroid Build Coastguard Worker           int i = 0, d = atolx(arg);
451*cf5a6c84SAndroid Build Coastguard Worker 
452*cf5a6c84SAndroid Build Coastguard Worker           while ((dt = dt->parent)) i++;
453*cf5a6c84SAndroid Build Coastguard Worker           if (s[1] == 'i') {
454*cf5a6c84SAndroid Build Coastguard Worker             test = i >= d;
455*cf5a6c84SAndroid Build Coastguard Worker             if (i == d && not) recurse = 0;
456*cf5a6c84SAndroid Build Coastguard Worker           } else {
457*cf5a6c84SAndroid Build Coastguard Worker             test = i <= d;
458*cf5a6c84SAndroid Build Coastguard Worker             if (i == d && !not) recurse = 0;
459*cf5a6c84SAndroid Build Coastguard Worker           }
460*cf5a6c84SAndroid Build Coastguard Worker         }
461*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "user") || !strcmp(s, "group")
462*cf5a6c84SAndroid Build Coastguard Worker               || !strncmp(s, "newer", 5) || !strcmp(s, "samefile"))
463*cf5a6c84SAndroid Build Coastguard Worker       {
464*cf5a6c84SAndroid Build Coastguard Worker         int macoff[] = {offsetof(struct stat, st_mtim),
465*cf5a6c84SAndroid Build Coastguard Worker           offsetof(struct stat, st_atim), offsetof(struct stat, st_ctim)};
466*cf5a6c84SAndroid Build Coastguard Worker         struct {
467*cf5a6c84SAndroid Build Coastguard Worker           void *next, *prev;
468*cf5a6c84SAndroid Build Coastguard Worker           union {
469*cf5a6c84SAndroid Build Coastguard Worker             uid_t uid;
470*cf5a6c84SAndroid Build Coastguard Worker             gid_t gid;
471*cf5a6c84SAndroid Build Coastguard Worker             struct timespec tm;
472*cf5a6c84SAndroid Build Coastguard Worker             struct dev_ino di;
473*cf5a6c84SAndroid Build Coastguard Worker           };
474*cf5a6c84SAndroid Build Coastguard Worker         } *udl;
475*cf5a6c84SAndroid Build Coastguard Worker         struct stat st;
476*cf5a6c84SAndroid Build Coastguard Worker 
477*cf5a6c84SAndroid Build Coastguard Worker         if (!new) {
478*cf5a6c84SAndroid Build Coastguard Worker           if (arg) {
479*cf5a6c84SAndroid Build Coastguard Worker             udl = xmalloc(sizeof(*udl));
480*cf5a6c84SAndroid Build Coastguard Worker             dlist_add_nomalloc(&TT.argdata, (void *)udl);
481*cf5a6c84SAndroid Build Coastguard Worker 
482*cf5a6c84SAndroid Build Coastguard Worker             if (strchr("sn", *s)) {
483*cf5a6c84SAndroid Build Coastguard Worker               if (*s=='n' && s[5] && (s[7] || !strchr("Bmac", s[5]) || !strchr("tBmac", s[6])))
484*cf5a6c84SAndroid Build Coastguard Worker                 goto error;
485*cf5a6c84SAndroid Build Coastguard Worker               if (*s=='s' || !s[5] || s[6]!='t') {
486*cf5a6c84SAndroid Build Coastguard Worker                 xstat(arg, &st);
487*cf5a6c84SAndroid Build Coastguard Worker                 if (*s=='s') udl->di.dev = st.st_dev, udl->di.ino = st.st_ino;
488*cf5a6c84SAndroid Build Coastguard Worker                 else udl->tm = *(struct timespec *)(((char *)&st)
489*cf5a6c84SAndroid Build Coastguard Worker                                + macoff[!s[5] ? 0 : stridx("ac", s[6])+1]);
490*cf5a6c84SAndroid Build Coastguard Worker               } else if (s[6] == 't') {
491*cf5a6c84SAndroid Build Coastguard Worker                 unsigned nano;
492*cf5a6c84SAndroid Build Coastguard Worker 
493*cf5a6c84SAndroid Build Coastguard Worker                 xparsedate(arg, &(udl->tm.tv_sec), &nano, 1);
494*cf5a6c84SAndroid Build Coastguard Worker                 udl->tm.tv_nsec = nano;
495*cf5a6c84SAndroid Build Coastguard Worker               }
496*cf5a6c84SAndroid Build Coastguard Worker             } else if (*s == 'u') udl->uid = xgetuid(arg);
497*cf5a6c84SAndroid Build Coastguard Worker             else udl->gid = xgetgid(arg);
498*cf5a6c84SAndroid Build Coastguard Worker           }
499*cf5a6c84SAndroid Build Coastguard Worker         } else {
500*cf5a6c84SAndroid Build Coastguard Worker           udl = (void *)llist_pop(&argdata);
501*cf5a6c84SAndroid Build Coastguard Worker           if (check) {
502*cf5a6c84SAndroid Build Coastguard Worker             if (*s == 'u') test = new->st.st_uid == udl->uid;
503*cf5a6c84SAndroid Build Coastguard Worker             else if (*s == 'g') test = new->st.st_gid == udl->gid;
504*cf5a6c84SAndroid Build Coastguard Worker             else if (*s == 's') test = same_dev_ino(&new->st, &udl->di);
505*cf5a6c84SAndroid Build Coastguard Worker             else {
506*cf5a6c84SAndroid Build Coastguard Worker               struct timespec *tm = (void *)(((char *)&new->st)
507*cf5a6c84SAndroid Build Coastguard Worker                 + macoff[!s[5] ? 0 : stridx("ac", s[5])+1]);
508*cf5a6c84SAndroid Build Coastguard Worker 
509*cf5a6c84SAndroid Build Coastguard Worker               if (s[5] == 'B') test = 0;
510*cf5a6c84SAndroid Build Coastguard Worker               else test = (tm->tv_sec == udl->tm.tv_sec)
511*cf5a6c84SAndroid Build Coastguard Worker                 ? tm->tv_nsec > udl->tm.tv_nsec
512*cf5a6c84SAndroid Build Coastguard Worker                 : tm->tv_sec > udl->tm.tv_sec;
513*cf5a6c84SAndroid Build Coastguard Worker             }
514*cf5a6c84SAndroid Build Coastguard Worker           }
515*cf5a6c84SAndroid Build Coastguard Worker         }
516*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "exec") || !strcmp("ok", s)
517*cf5a6c84SAndroid Build Coastguard Worker               || !strcmp(s, "execdir") || !strcmp(s, "okdir"))
518*cf5a6c84SAndroid Build Coastguard Worker       {
519*cf5a6c84SAndroid Build Coastguard Worker         struct exec_range *aa;
520*cf5a6c84SAndroid Build Coastguard Worker 
521*cf5a6c84SAndroid Build Coastguard Worker         print++;
522*cf5a6c84SAndroid Build Coastguard Worker 
523*cf5a6c84SAndroid Build Coastguard Worker         // Initial argument parsing pass
524*cf5a6c84SAndroid Build Coastguard Worker         if (!new) {
525*cf5a6c84SAndroid Build Coastguard Worker           int len;
526*cf5a6c84SAndroid Build Coastguard Worker 
527*cf5a6c84SAndroid Build Coastguard Worker           // catch "-exec" with no args and "-exec \;"
528*cf5a6c84SAndroid Build Coastguard Worker           if (!arg || !strcmp(arg, ";")) error_exit("'%s' needs 1 arg", s);
529*cf5a6c84SAndroid Build Coastguard Worker 
530*cf5a6c84SAndroid Build Coastguard Worker           dlist_add_nomalloc(&TT.argdata, (void *)(aa = xzalloc(sizeof(*aa))));
531*cf5a6c84SAndroid Build Coastguard Worker           aa->argstart = ss;
532*cf5a6c84SAndroid Build Coastguard Worker           aa->curly = -1;
533*cf5a6c84SAndroid Build Coastguard Worker 
534*cf5a6c84SAndroid Build Coastguard Worker           // Record command line arguments to -exec
535*cf5a6c84SAndroid Build Coastguard Worker           for (len = 0; ss[len]; len++) {
536*cf5a6c84SAndroid Build Coastguard Worker             if (!strcmp(ss[len], ";")) break;
537*cf5a6c84SAndroid Build Coastguard Worker             else if (!strcmp(ss[len], "{}")) {
538*cf5a6c84SAndroid Build Coastguard Worker               aa->curly = len;
539*cf5a6c84SAndroid Build Coastguard Worker               if (ss[len+1] && !strcmp(ss[len+1], "+")) {
540*cf5a6c84SAndroid Build Coastguard Worker                 aa->plus++;
541*cf5a6c84SAndroid Build Coastguard Worker                 len++;
542*cf5a6c84SAndroid Build Coastguard Worker                 break;
543*cf5a6c84SAndroid Build Coastguard Worker               }
544*cf5a6c84SAndroid Build Coastguard Worker             } else aa->argsize += sizeof(char *) + strlen(ss[len]) + 1;
545*cf5a6c84SAndroid Build Coastguard Worker           }
546*cf5a6c84SAndroid Build Coastguard Worker           if (!ss[len]) error_exit("-exec without %s",
547*cf5a6c84SAndroid Build Coastguard Worker             aa->curly!=-1 ? "\\;" : "{}");
548*cf5a6c84SAndroid Build Coastguard Worker           ss += len;
549*cf5a6c84SAndroid Build Coastguard Worker           aa->arglen = len;
550*cf5a6c84SAndroid Build Coastguard Worker           aa->dir = !!strchr(s, 'd');
551*cf5a6c84SAndroid Build Coastguard Worker           if (TT.topdir == -1) TT.topdir = xopenro(".");
552*cf5a6c84SAndroid Build Coastguard Worker 
553*cf5a6c84SAndroid Build Coastguard Worker         // collect names and execute commands
554*cf5a6c84SAndroid Build Coastguard Worker         } else {
555*cf5a6c84SAndroid Build Coastguard Worker           char *name;
556*cf5a6c84SAndroid Build Coastguard Worker           struct execdir_data *bb;
557*cf5a6c84SAndroid Build Coastguard Worker 
558*cf5a6c84SAndroid Build Coastguard Worker           // Grab command line exec argument list
559*cf5a6c84SAndroid Build Coastguard Worker           aa = (void *)llist_pop(&argdata);
560*cf5a6c84SAndroid Build Coastguard Worker           ss += aa->arglen;
561*cf5a6c84SAndroid Build Coastguard Worker 
562*cf5a6c84SAndroid Build Coastguard Worker           if (!check) goto cont;
563*cf5a6c84SAndroid Build Coastguard Worker           // name is always a new malloc, so we can always free it.
564*cf5a6c84SAndroid Build Coastguard Worker           name = aa->dir ? xstrdup(new->name) : dirtree_path(new, 0);
565*cf5a6c84SAndroid Build Coastguard Worker 
566*cf5a6c84SAndroid Build Coastguard Worker           if (*s == 'o') {
567*cf5a6c84SAndroid Build Coastguard Worker             fprintf(stderr, "[%s] %s", arg, name);
568*cf5a6c84SAndroid Build Coastguard Worker             if (!(test = yesno(0))) {
569*cf5a6c84SAndroid Build Coastguard Worker               free(name);
570*cf5a6c84SAndroid Build Coastguard Worker               goto cont;
571*cf5a6c84SAndroid Build Coastguard Worker             }
572*cf5a6c84SAndroid Build Coastguard Worker           }
573*cf5a6c84SAndroid Build Coastguard Worker 
574*cf5a6c84SAndroid Build Coastguard Worker           // Add next name to list (global list without -dir, local with)
575*cf5a6c84SAndroid Build Coastguard Worker           bb = aa->execdir ? aa->execdir : &aa->exec;
576*cf5a6c84SAndroid Build Coastguard Worker           dlist_add(&bb->names, name);
577*cf5a6c84SAndroid Build Coastguard Worker           bb->namecount++;
578*cf5a6c84SAndroid Build Coastguard Worker 
579*cf5a6c84SAndroid Build Coastguard Worker           // -exec + collates and saves result in exitval
580*cf5a6c84SAndroid Build Coastguard Worker           if (aa->plus) {
581*cf5a6c84SAndroid Build Coastguard Worker             // Mark entry so COMEAGAIN can call flush_exec() in parent.
582*cf5a6c84SAndroid Build Coastguard Worker             // This is never a valid pointer value for prev to have otherwise
583*cf5a6c84SAndroid Build Coastguard Worker             // Done here vs argument parsing pass so it's after dlist_terminate
584*cf5a6c84SAndroid Build Coastguard Worker             aa->prev = (void *)1;
585*cf5a6c84SAndroid Build Coastguard Worker 
586*cf5a6c84SAndroid Build Coastguard Worker             // Flush if the child's environment space gets too large.
587*cf5a6c84SAndroid Build Coastguard Worker             // Linux caps individual arguments/variables at 131072 bytes,
588*cf5a6c84SAndroid Build Coastguard Worker             // so this counter can't wrap.
589*cf5a6c84SAndroid Build Coastguard Worker             if ((aa->plus += sizeof(char *)+strlen(name)+1) > TT.max_bytes) {
590*cf5a6c84SAndroid Build Coastguard Worker               aa->plus = 1;
591*cf5a6c84SAndroid Build Coastguard Worker               toys.exitval |= flush_exec(new, aa);
592*cf5a6c84SAndroid Build Coastguard Worker             }
593*cf5a6c84SAndroid Build Coastguard Worker           } else test = !flush_exec(new, aa);
594*cf5a6c84SAndroid Build Coastguard Worker         }
595*cf5a6c84SAndroid Build Coastguard Worker 
596*cf5a6c84SAndroid Build Coastguard Worker         // Argument consumed, skip the check.
597*cf5a6c84SAndroid Build Coastguard Worker         goto cont;
598*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(s, "printf")) {
599*cf5a6c84SAndroid Build Coastguard Worker         char *fmt, *ff, next[32], buf[64], ch;
600*cf5a6c84SAndroid Build Coastguard Worker         long ll;
601*cf5a6c84SAndroid Build Coastguard Worker         int len;
602*cf5a6c84SAndroid Build Coastguard Worker 
603*cf5a6c84SAndroid Build Coastguard Worker         print++;
604*cf5a6c84SAndroid Build Coastguard Worker         if (check) for (fmt = arg; *fmt; fmt++) {
605*cf5a6c84SAndroid Build Coastguard Worker           // Print the parts that aren't escapes
606*cf5a6c84SAndroid Build Coastguard Worker           if (*fmt == '\\') {
607*cf5a6c84SAndroid Build Coastguard Worker             unsigned u;
608*cf5a6c84SAndroid Build Coastguard Worker 
609*cf5a6c84SAndroid Build Coastguard Worker             if (fmt[1] == 'c') break;
610*cf5a6c84SAndroid Build Coastguard Worker             if ((u = unescape2(&fmt, 0))<128) putchar(u);
611*cf5a6c84SAndroid Build Coastguard Worker             else printf("%.*s", (int)wcrtomb(buf, u, 0), buf);
612*cf5a6c84SAndroid Build Coastguard Worker             fmt--;
613*cf5a6c84SAndroid Build Coastguard Worker           } else if (*fmt != '%') putchar(*fmt);
614*cf5a6c84SAndroid Build Coastguard Worker           else if (*++fmt == '%') putchar('%');
615*cf5a6c84SAndroid Build Coastguard Worker           else {
616*cf5a6c84SAndroid Build Coastguard Worker             fmt = next_printf(ff = fmt-1, 0);
617*cf5a6c84SAndroid Build Coastguard Worker             if ((len = fmt-ff)>28) error_exit("bad %.*s", len+1, ff);
618*cf5a6c84SAndroid Build Coastguard Worker             memcpy(next, ff, len);
619*cf5a6c84SAndroid Build Coastguard Worker             ff = 0;
620*cf5a6c84SAndroid Build Coastguard Worker             ch = *fmt;
621*cf5a6c84SAndroid Build Coastguard Worker 
622*cf5a6c84SAndroid Build Coastguard Worker             // long long is its own stack size on LP64, so handle separately
623*cf5a6c84SAndroid Build Coastguard Worker             if (ch == 'i' || ch == 's') {
624*cf5a6c84SAndroid Build Coastguard Worker               strcpy(next+len, "lld");
625*cf5a6c84SAndroid Build Coastguard Worker               printf(next, (ch == 'i') ? (long long)new->st.st_ino
626*cf5a6c84SAndroid Build Coastguard Worker                 : (long long)new->st.st_size);
627*cf5a6c84SAndroid Build Coastguard Worker             } else {
628*cf5a6c84SAndroid Build Coastguard Worker 
629*cf5a6c84SAndroid Build Coastguard Worker               // LP64 says these are all a single "long" argument to printf
630*cf5a6c84SAndroid Build Coastguard Worker               strcpy(next+len, "s");
631*cf5a6c84SAndroid Build Coastguard Worker               if (ch == 'G') next[len] = 'd', ll = new->st.st_gid;
632*cf5a6c84SAndroid Build Coastguard Worker               else if (ch == 'm') next[len] = 'o', ll = new->st.st_mode&~S_IFMT;
633*cf5a6c84SAndroid Build Coastguard Worker               else if (ch == 'U') next[len] = 'd', ll = new->st.st_uid;
634*cf5a6c84SAndroid Build Coastguard Worker               else if (ch == 'f') ll = (long)new->name;
635*cf5a6c84SAndroid Build Coastguard Worker               else if (ch == 'g') ll = (long)getgroupname(new->st.st_gid);
636*cf5a6c84SAndroid Build Coastguard Worker               else if (ch == 'u') ll = (long)getusername(new->st.st_uid);
637*cf5a6c84SAndroid Build Coastguard Worker               else if (ch == 'l') {
638*cf5a6c84SAndroid Build Coastguard Worker                 ll = (long)(ff = xreadlinkat(dirtree_parentfd(new), new->name));
639*cf5a6c84SAndroid Build Coastguard Worker                 if (!ll) ll = (long)"";
640*cf5a6c84SAndroid Build Coastguard Worker               } else if (ch == 'M') {
641*cf5a6c84SAndroid Build Coastguard Worker                 mode_to_string(new->st.st_mode, buf);
642*cf5a6c84SAndroid Build Coastguard Worker                 ll = (long)buf;
643*cf5a6c84SAndroid Build Coastguard Worker               } else if (ch == 'P') {
644*cf5a6c84SAndroid Build Coastguard Worker                 ch = *TT.start;
645*cf5a6c84SAndroid Build Coastguard Worker                 *TT.start = 0;
646*cf5a6c84SAndroid Build Coastguard Worker                 ll = (long)(ff = dirtree_path(new, 0));
647*cf5a6c84SAndroid Build Coastguard Worker                 *TT.start = ch;
648*cf5a6c84SAndroid Build Coastguard Worker               } else if (ch == 'p') ll = (long)(ff = dirtree_path(new, 0));
649*cf5a6c84SAndroid Build Coastguard Worker               else if (ch == 'T') {
650*cf5a6c84SAndroid Build Coastguard Worker                 if (*++fmt!='@') error_exit("bad -printf %%T: %%T%c", *fmt);
651*cf5a6c84SAndroid Build Coastguard Worker                 sprintf(buf, "%lld.%ld", (long long)new->st.st_mtim.tv_sec,
652*cf5a6c84SAndroid Build Coastguard Worker                              new->st.st_mtim.tv_nsec);
653*cf5a6c84SAndroid Build Coastguard Worker                 ll = (long)buf;
654*cf5a6c84SAndroid Build Coastguard Worker               } else if (ch == 'Z') {
655*cf5a6c84SAndroid Build Coastguard Worker                 char *path = dirtree_path(new, 0);
656*cf5a6c84SAndroid Build Coastguard Worker 
657*cf5a6c84SAndroid Build Coastguard Worker                 ll = (lsm_get_context(path, &ff) != -1) ? (long)ff : (long)"?";
658*cf5a6c84SAndroid Build Coastguard Worker                 free(path);
659*cf5a6c84SAndroid Build Coastguard Worker               } else error_exit("bad -printf %%%c", ch);
660*cf5a6c84SAndroid Build Coastguard Worker 
661*cf5a6c84SAndroid Build Coastguard Worker               printf(next, ll);
662*cf5a6c84SAndroid Build Coastguard Worker               free(ff);
663*cf5a6c84SAndroid Build Coastguard Worker             }
664*cf5a6c84SAndroid Build Coastguard Worker           }
665*cf5a6c84SAndroid Build Coastguard Worker         }
666*cf5a6c84SAndroid Build Coastguard Worker       } else goto error;
667*cf5a6c84SAndroid Build Coastguard Worker 
668*cf5a6c84SAndroid Build Coastguard Worker       // This test can go at the end because we do a syntax checking
669*cf5a6c84SAndroid Build Coastguard Worker       // pass first. Putting it here gets the error message (-unknown
670*cf5a6c84SAndroid Build Coastguard Worker       // vs -known noarg) right.
671*cf5a6c84SAndroid Build Coastguard Worker       if (!check && !arg) error_exit("'%s' needs 1 arg", s-1);
672*cf5a6c84SAndroid Build Coastguard Worker     }
673*cf5a6c84SAndroid Build Coastguard Worker cont:
674*cf5a6c84SAndroid Build Coastguard Worker     // Apply pending "!" to result
675*cf5a6c84SAndroid Build Coastguard Worker     if (active && not) test = !test;
676*cf5a6c84SAndroid Build Coastguard Worker     not = 0;
677*cf5a6c84SAndroid Build Coastguard Worker   }
678*cf5a6c84SAndroid Build Coastguard Worker 
679*cf5a6c84SAndroid Build Coastguard Worker   if (new) {
680*cf5a6c84SAndroid Build Coastguard Worker     // If there was no action, print
681*cf5a6c84SAndroid Build Coastguard Worker     if (!print && test) do_print(new, '\n');
682*cf5a6c84SAndroid Build Coastguard Worker 
683*cf5a6c84SAndroid Build Coastguard Worker     if (S_ISDIR(new->st.st_mode)) execdir(new, 0);
684*cf5a6c84SAndroid Build Coastguard Worker 
685*cf5a6c84SAndroid Build Coastguard Worker   } else dlist_terminate(TT.argdata);
686*cf5a6c84SAndroid Build Coastguard Worker 
687*cf5a6c84SAndroid Build Coastguard Worker   return recurse;
688*cf5a6c84SAndroid Build Coastguard Worker 
689*cf5a6c84SAndroid Build Coastguard Worker error:
690*cf5a6c84SAndroid Build Coastguard Worker   if (!*ss) --ss;
691*cf5a6c84SAndroid Build Coastguard Worker   error_exit("bad arg '%s'", *ss);
692*cf5a6c84SAndroid Build Coastguard Worker }
693*cf5a6c84SAndroid Build Coastguard Worker 
find_main(void)694*cf5a6c84SAndroid Build Coastguard Worker void find_main(void)
695*cf5a6c84SAndroid Build Coastguard Worker {
696*cf5a6c84SAndroid Build Coastguard Worker   int i, len;
697*cf5a6c84SAndroid Build Coastguard Worker   char **ss = (char *[]){"."};
698*cf5a6c84SAndroid Build Coastguard Worker 
699*cf5a6c84SAndroid Build Coastguard Worker   TT.topdir = -1;
700*cf5a6c84SAndroid Build Coastguard Worker   TT.max_bytes = sysconf(_SC_ARG_MAX) - environ_bytes();
701*cf5a6c84SAndroid Build Coastguard Worker 
702*cf5a6c84SAndroid Build Coastguard Worker   // Distinguish paths from filters
703*cf5a6c84SAndroid Build Coastguard Worker   for (len = 0; toys.optargs[len]; len++)
704*cf5a6c84SAndroid Build Coastguard Worker     if (*toys.optargs[len] && strchr("-!(", *toys.optargs[len])) break;
705*cf5a6c84SAndroid Build Coastguard Worker   TT.filter = toys.optargs+len;
706*cf5a6c84SAndroid Build Coastguard Worker 
707*cf5a6c84SAndroid Build Coastguard Worker   // use "." if no paths
708*cf5a6c84SAndroid Build Coastguard Worker   if (len) ss = toys.optargs;
709*cf5a6c84SAndroid Build Coastguard Worker   else len = 1;
710*cf5a6c84SAndroid Build Coastguard Worker 
711*cf5a6c84SAndroid Build Coastguard Worker   // first pass argument parsing, verify args match up, handle "evaluate once"
712*cf5a6c84SAndroid Build Coastguard Worker   TT.now = time(0);
713*cf5a6c84SAndroid Build Coastguard Worker   do_find(0);
714*cf5a6c84SAndroid Build Coastguard Worker 
715*cf5a6c84SAndroid Build Coastguard Worker   // Loop through paths
716*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0; i < len; i++)
717*cf5a6c84SAndroid Build Coastguard Worker     dirtree_flagread(ss[i],
718*cf5a6c84SAndroid Build Coastguard Worker       DIRTREE_STATLESS|(DIRTREE_SYMFOLLOW*!!(toys.optflags&(FLAG_H|FLAG_L))),
719*cf5a6c84SAndroid Build Coastguard Worker       do_find);
720*cf5a6c84SAndroid Build Coastguard Worker 
721*cf5a6c84SAndroid Build Coastguard Worker   execdir(0, 1);
722*cf5a6c84SAndroid Build Coastguard Worker 
723*cf5a6c84SAndroid Build Coastguard Worker   if (CFG_TOYBOX_FREE) {
724*cf5a6c84SAndroid Build Coastguard Worker     close(TT.topdir);
725*cf5a6c84SAndroid Build Coastguard Worker     llist_traverse(TT.argdata, free);
726*cf5a6c84SAndroid Build Coastguard Worker   }
727*cf5a6c84SAndroid Build Coastguard Worker }
728