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