aboutsummaryrefslogtreecommitdiff
path: root/findutils/find.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-10-29 19:07:01 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-10-29 19:07:01 +0000
commit5d499e1600e2fd627fba035faf3cb78f6333dcde (patch)
tree52f5401ce1e1ee881aaa656ce94764a92fad7609 /findutils/find.c
parente2fb719ba3463955f349ce63228981943f00bfaa (diff)
downloadbusybox-w32-5d499e1600e2fd627fba035faf3cb78f6333dcde.tar.gz
busybox-w32-5d499e1600e2fd627fba035faf3cb78f6333dcde.tar.bz2
busybox-w32-5d499e1600e2fd627fba035faf3cb78f6333dcde.zip
find: a lot more compliant to 'standard' find
(we were not respecting order of actions!). Add -o and -a handling.
Diffstat (limited to 'findutils/find.c')
-rw-r--r--findutils/find.c433
1 files changed, 260 insertions, 173 deletions
diff --git a/findutils/find.c b/findutils/find.c
index a3cbe668d..abd757662 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -23,62 +23,46 @@
23 * # find file.txt -exec 'echo' '{} {}' ';' 23 * # find file.txt -exec 'echo' '{} {}' ';'
24 * file.txt file.txt 24 * file.txt file.txt
25 * (strace: execve("/bin/echo", ["echo", "file.txt file.txt"], [ 30 vars ])) 25 * (strace: execve("/bin/echo", ["echo", "file.txt file.txt"], [ 30 vars ]))
26 *
27 * bboxed find rev 16467: above - works, below - doesn't
28 *
29 * # find file.txt -exec 'echo' '{} {}' ';' -print -exec pwd ';' 26 * # find file.txt -exec 'echo' '{} {}' ';' -print -exec pwd ';'
30 * file.txt file.txt 27 * file.txt file.txt
31 * file.txt 28 * file.txt
32 * /tmp 29 * /tmp
33 * # find -name '*.c' -o -name '*.h' 30 * # find -name '*.c' -o -name '*.h'
34 * [shows files, *.c and *.h intermixed] 31 * [shows files, *.c and *.h intermixed]
32 * # find file.txt -name '*f*' -o -name '*t*'
33 * file.txt
34 * # find file.txt -name '*z*' -o -name '*t*'
35 * file.txt
36 * # find file.txt -name '*f*' -o -name '*z*'
37 * file.txt
35 */ 38 */
36 39
37#include "busybox.h" 40#include "busybox.h"
38#include <fnmatch.h> 41#include <fnmatch.h>
39 42
40static char *pattern; 43USE_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
41#if ENABLE_FEATURE_FIND_PRINT0 44USE_FEATURE_FIND_XDEV(static int xdev_count;)
42static char printsep = '\n';
43#endif
44
45#if ENABLE_FEATURE_FIND_TYPE
46static int type_mask = 0;
47#endif
48
49#if ENABLE_FEATURE_FIND_PERM
50static char perm_char = 0;
51static int perm_mask = 0;
52#endif
53
54#if ENABLE_FEATURE_FIND_MTIME
55static char mtime_char;
56static int mtime_days;
57#endif
58
59#if ENABLE_FEATURE_FIND_MMIN
60static char mmin_char;
61static int mmin_mins;
62#endif
63 45
64#if ENABLE_FEATURE_FIND_XDEV 46typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *);
65static dev_t *xdev_dev;
66static int xdev_count = 0;
67#endif
68 47
69#if ENABLE_FEATURE_FIND_NEWER 48typedef struct {
70static time_t newer_mtime; 49 action_fp f;
71#endif 50} action;
51#define SACT(name, arg...) typedef struct { action a; arg; } action_##name;
52#define SFUNC(name) static int func_##name(const char *fileName, struct stat *statbuf, action_##name* ap)
53 SACT(print)
54 SACT(name, char *pattern;)
55USE_FEATURE_FIND_PRINT0(SACT(print0))
56USE_FEATURE_FIND_TYPE( SACT(type, int type_mask;))
57USE_FEATURE_FIND_PERM( SACT(perm, char perm_char; int perm_mask;))
58USE_FEATURE_FIND_MTIME( SACT(mtime, char mtime_char; int mtime_days;))
59USE_FEATURE_FIND_MMIN( SACT(mmin, char mmin_char; int mmin_mins;))
60USE_FEATURE_FIND_NEWER( SACT(newer, time_t newer_mtime;))
61USE_FEATURE_FIND_INUM( SACT(inum, ino_t inode_num;))
62USE_FEATURE_FIND_EXEC( SACT(exec, char **exec_argv; int *subst_count; int exec_argc;))
72 63
73#if ENABLE_FEATURE_FIND_INUM 64static action ***actions;
74static ino_t inode_num;
75#endif
76 65
77#if ENABLE_FEATURE_FIND_EXEC
78static char **exec_argv;
79static int *subst_count;
80static int exec_argc;
81#endif
82 66
83static int count_subst(const char *str) 67static int count_subst(const char *str)
84{ 68{
@@ -109,102 +93,116 @@ static char* subst(const char *src, int count, const char* filename)
109} 93}
110 94
111 95
112static int fileAction(const char *fileName, struct stat *statbuf, void* junk, int depth) 96SFUNC(name)
113{ 97{
114#if ENABLE_FEATURE_FIND_XDEV 98 const char *tmp = strrchr(fileName, '/');
115 if (S_ISDIR(statbuf->st_mode) && xdev_count) { 99 if (tmp == NULL)
116 int i; 100 tmp = fileName;
117 for (i=0; i<xdev_count; i++) { 101 else
118 if (xdev_dev[i] != statbuf->st_dev) 102 tmp++;
119 return SKIP; 103 return fnmatch(ap->pattern, tmp, FNM_PERIOD) == 0;
120 } 104}
121 }
122#endif
123 if (pattern != NULL) {
124 const char *tmp = strrchr(fileName, '/');
125
126 if (tmp == NULL)
127 tmp = fileName;
128 else
129 tmp++;
130 if (fnmatch(pattern, tmp, FNM_PERIOD) != 0)
131 goto no_match;
132 }
133#if ENABLE_FEATURE_FIND_TYPE 105#if ENABLE_FEATURE_FIND_TYPE
134 if (type_mask != 0) { 106SFUNC(type)
135 if (!((statbuf->st_mode & S_IFMT) == type_mask)) 107{
136 goto no_match; 108 return !((statbuf->st_mode & S_IFMT) == ap->type_mask);
137 } 109}
138#endif 110#endif
139#if ENABLE_FEATURE_FIND_PERM 111#if ENABLE_FEATURE_FIND_PERM
140 if (perm_mask != 0) { 112SFUNC(perm)
141 if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) || 113{
142 (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) || 114 return !((isdigit(ap->perm_char) && (statbuf->st_mode & 07777) == ap->perm_mask)
143 (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0))) 115 || (ap->perm_char == '-' && (statbuf->st_mode & ap->perm_mask) == ap->perm_mask)
144 goto no_match; 116 || (ap->perm_char == '+' && (statbuf->st_mode & ap->perm_mask) != 0));
145 } 117}
146#endif 118#endif
147#if ENABLE_FEATURE_FIND_MTIME 119#if ENABLE_FEATURE_FIND_MTIME
148 if (mtime_char != 0) { 120SFUNC(mtime)
149 time_t file_age = time(NULL) - statbuf->st_mtime; 121{
150 time_t mtime_secs = mtime_days * 24 * 60 * 60; 122 time_t file_age = time(NULL) - statbuf->st_mtime;
151 if (!((isdigit(mtime_char) && file_age >= mtime_secs && 123 time_t mtime_secs = ap->mtime_days * 24 * 60 * 60;
152 file_age < mtime_secs + 24 * 60 * 60) || 124 return !((isdigit(ap->mtime_char) && file_age >= mtime_secs
153 (mtime_char == '+' && file_age >= mtime_secs + 24 * 60 * 60) || 125 && file_age < mtime_secs + 24 * 60 * 60)
154 (mtime_char == '-' && file_age < mtime_secs))) 126 || (ap->mtime_char == '+' && file_age >= mtime_secs + 24 * 60 * 60)
155 goto no_match; 127 || (ap->mtime_char == '-' && file_age < mtime_secs));
156 } 128}
157#endif 129#endif
158#if ENABLE_FEATURE_FIND_MMIN 130#if ENABLE_FEATURE_FIND_MMIN
159 if (mmin_char != 0) { 131SFUNC(mmin)
160 time_t file_age = time(NULL) - statbuf->st_mtime; 132{
161 time_t mmin_secs = mmin_mins * 60; 133 time_t file_age = time(NULL) - statbuf->st_mtime;
162 if (!((isdigit(mmin_char) && file_age >= mmin_secs && 134 time_t mmin_secs = ap->mmin_mins * 60;
163 file_age < mmin_secs + 60) || 135 return !((isdigit(ap->mmin_char) && file_age >= mmin_secs
164 (mmin_char == '+' && file_age >= mmin_secs + 60) || 136 && file_age < mmin_secs + 60)
165 (mmin_char == '-' && file_age < mmin_secs))) 137 || (ap->mmin_char == '+' && file_age >= mmin_secs + 60)
166 goto no_match; 138 || (ap->mmin_char == '-' && file_age < mmin_secs));
167 } 139}
168#endif 140#endif
169#if ENABLE_FEATURE_FIND_NEWER 141#if ENABLE_FEATURE_FIND_NEWER
170 if (newer_mtime != 0) { 142SFUNC(newer)
171 time_t file_age = newer_mtime - statbuf->st_mtime; 143{
172 if (file_age >= 0) 144 return (ap->newer_mtime >= statbuf->st_mtime);
173 goto no_match; 145}
174 }
175#endif 146#endif
176#if ENABLE_FEATURE_FIND_INUM 147#if ENABLE_FEATURE_FIND_INUM
177 if (inode_num != 0) { 148SFUNC(inum)
178 if (!(statbuf->st_ino == inode_num)) 149{
179 goto no_match; 150 return (statbuf->st_ino != ap->inode_num);
180 } 151}
181#endif 152#endif
182#if ENABLE_FEATURE_FIND_EXEC 153#if ENABLE_FEATURE_FIND_EXEC
183 if (exec_argc) { 154SFUNC(exec)
184 int i; 155{
185 char *argv[exec_argc+1]; 156 int i, rc;
186 for (i = 0; i < exec_argc; i++) 157 char *argv[ap->exec_argc+1];
187 argv[i] = subst(exec_argv[i], subst_count[i], fileName); 158 for (i = 0; i < ap->exec_argc; i++)
188 argv[i] = NULL; /* terminate the list */ 159 argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName);
189 errno = 0; 160 argv[i] = NULL; /* terminate the list */
190 wait4pid(spawn(argv)); 161 errno = 0;
191 if (errno) 162 rc = wait4pid(spawn(argv));
192 bb_perror_msg("%s", argv[0]); 163 if (errno)
193 for (i = 0; i < exec_argc; i++) 164 bb_perror_msg("%s", argv[0]);
194 free(argv[i]); 165 for (i = 0; i < ap->exec_argc; i++)
195 goto no_match; 166 free(argv[i]);
196 } 167 return rc == 0; /* return 1 if success */
168}
197#endif 169#endif
198 170
199#if ENABLE_FEATURE_FIND_PRINT0 171#if ENABLE_FEATURE_FIND_PRINT0
200 printf("%s%c", fileName, printsep); 172SFUNC(print0)
201#else 173{
202 puts(fileName); 174 printf("%s%c", fileName, '\0');
175 return TRUE;
176}
203#endif 177#endif
204 no_match: 178SFUNC(print)
179{
180 puts(fileName);
205 return TRUE; 181 return TRUE;
206} 182}
207 183
184
185static int fileAction(const char *fileName, struct stat *statbuf, void* junk, int depth)
186{
187 int cur_group;
188 int cur_action;
189 action **app, *ap;
190
191 cur_group = -1;
192 while ((app = actions[++cur_group])) {
193 cur_action = -1;
194 do {
195 ap = app[++cur_action];
196 } while (ap && ap->f(fileName, statbuf, ap));
197 if (!ap) {
198 /* all actions in group were successful */
199 break;
200 }
201 }
202 return TRUE;
203}
204
205
208#if ENABLE_FEATURE_FIND_TYPE 206#if ENABLE_FEATURE_FIND_TYPE
209static int find_type(char *type) 207static int find_type(char *type)
210{ 208{
@@ -241,38 +239,127 @@ static int find_type(char *type)
241} 239}
242#endif 240#endif
243 241
242
244int find_main(int argc, char **argv) 243int find_main(int argc, char **argv)
245{ 244{
246 int dereference = FALSE; 245 int dereference = FALSE;
247 int i, j, firstopt, status = EXIT_SUCCESS; 246 int i, j, firstopt, status = EXIT_SUCCESS;
247 int cur_group;
248 int cur_action;
249 int need_default = 1;
250
251 action* alloc_action(int sizeof_struct, action_fp f)
252 {
253 action *ap;
254 actions[cur_group] = xrealloc(actions[cur_group], (cur_action+2) * sizeof(*actions));
255 actions[cur_group][cur_action++] = ap = xmalloc(sizeof_struct);
256 actions[cur_group][cur_action] = NULL;
257 ap->f = f;
258 return ap;
259 }
260#define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name)
248 261
249 for (firstopt = 1; firstopt < argc; firstopt++) { 262 for (firstopt = 1; firstopt < argc; firstopt++) {
250 if (argv[firstopt][0] == '-') 263 if (argv[firstopt][0] == '-')
251 break; 264 break;
252 } 265 }
266 if (firstopt == 1) {
267 argv[0] = ".";
268 argv--;
269 argc++;
270 firstopt++;
271 }
272
273// All options always return true. They always take effect,
274// rather than being processed only when their place in the
275// expression is reached
276// We implement: -follow, -xdev
277
278// Actions have side effects and return a true or false value
279// We implement: -print, -print0, -exec
280
281// The rest are tests.
282
283// Tests and actions are grouped by operators
284// ( expr ) Force precedence
285// ! expr True if expr is false
286// -not expr Same as ! expr
287// expr1 [-a[nd]] expr2 And; expr2 is not evaluated if expr1 is false
288// expr1 -o[r] expr2 Or; expr2 is not evaluated if expr1 is true
289// expr1 , expr2 List; both expr1 and expr2 are always evaluated
290// We implement: -a, -o
291
292 cur_group = 0;
293 cur_action = 0;
294 actions = xzalloc(sizeof(*actions)); /* actions[0] == NULL */
253 295
254 /* Parse any options */ 296 /* Parse any options */
255 for (i = firstopt; i < argc; i++) { 297 for (i = firstopt; i < argc; i++) {
256 char *arg = argv[i]; 298 char *arg = argv[i];
257 char *arg1 = argv[i+1]; 299 char *arg1 = argv[i+1];
258 if (strcmp(arg, "-follow") == 0) 300
301 /* --- Operators --- */
302 if (ENABLE_DESKTOP
303 && (strcmp(arg, "-a") == 0 || strcmp(arg, "-and") == 0)
304 ) {
305 /* no special handling required */
306 }
307 else if (strcmp(arg, "-o") == 0
308 USE_DESKTOP(|| strcmp(arg, "-or") == 0)
309 ) {
310 if (need_default)
311 (void) ALLOC_ACTION(print);
312 cur_group++;
313 actions = xrealloc(actions, (cur_group+1) * sizeof(*actions));
314 actions[cur_group] = NULL;
315 actions[cur_group+1] = NULL;
316 cur_action = 0;
317 need_default = 1;
318 }
319
320 /* --- Options --- */
321 else if (strcmp(arg, "-follow") == 0)
259 dereference = TRUE; 322 dereference = TRUE;
323#if ENABLE_FEATURE_FIND_XDEV
324 else if (strcmp(arg, "-xdev") == 0) {
325 struct stat stbuf;
326
327 xdev_count = firstopt - 1;
328 xdev_dev = xmalloc(xdev_count * sizeof(dev_t));
329 for (j = 1; j < firstopt; i++) {
330 /* not xstat(): shouldn't bomd out on
331 * "find not_exist exist -xdev" */
332 if (stat(argv[j], &stbuf)) stbuf.st_dev = -1L;
333 xdev_dev[j-1] = stbuf.st_dev;
334 }
335 }
336#endif
337 /* --- Tests and actions --- */
260 else if (strcmp(arg, "-print") == 0) { 338 else if (strcmp(arg, "-print") == 0) {
261 ; 339 need_default = 0;
340 (void) ALLOC_ACTION(print);
262 } 341 }
263#if ENABLE_FEATURE_FIND_PRINT0 342#if ENABLE_FEATURE_FIND_PRINT0
264 else if (strcmp(arg, "-print0") == 0) 343 else if (strcmp(arg, "-print0") == 0) {
265 printsep = '\0'; 344 need_default = 0;
345 (void) ALLOC_ACTION(print0);
346 }
266#endif 347#endif
267 else if (strcmp(arg, "-name") == 0) { 348 else if (strcmp(arg, "-name") == 0) {
349 action_name *ap;
268 if (++i == argc) 350 if (++i == argc)
269 bb_error_msg_and_die(bb_msg_requires_arg, arg); 351 bb_error_msg_and_die(bb_msg_requires_arg, arg);
270 pattern = arg1; 352 ap = ALLOC_ACTION(name);
353 ap->pattern = arg1;
354 }
271#if ENABLE_FEATURE_FIND_TYPE 355#if ENABLE_FEATURE_FIND_TYPE
272 } else if (strcmp(arg, "-type") == 0) { 356 else if (strcmp(arg, "-type") == 0) {
357 action_type *ap;
273 if (++i == argc) 358 if (++i == argc)
274 bb_error_msg_and_die(bb_msg_requires_arg, arg); 359 bb_error_msg_and_die(bb_msg_requires_arg, arg);
275 type_mask = find_type(arg1); 360 ap = ALLOC_ACTION(type);
361 ap->type_mask = find_type(arg1);
362 }
276#endif 363#endif
277#if ENABLE_FEATURE_FIND_PERM 364#if ENABLE_FEATURE_FIND_PERM
278/* TODO: 365/* TODO:
@@ -281,68 +368,69 @@ int find_main(int argc, char **argv)
281 * -perm -mode All of the permission bits mode are set for the file. 368 * -perm -mode All of the permission bits mode are set for the file.
282 * -perm +mode Any of the permission bits mode are set for the file. 369 * -perm +mode Any of the permission bits mode are set for the file.
283 */ 370 */
284 } else if (strcmp(arg, "-perm") == 0) { 371 else if (strcmp(arg, "-perm") == 0) {
372 action_perm *ap;
285 if (++i == argc) 373 if (++i == argc)
286 bb_error_msg_and_die(bb_msg_requires_arg, arg); 374 bb_error_msg_and_die(bb_msg_requires_arg, arg);
287 perm_mask = xstrtol_range(arg1, 8, 0, 07777); 375 ap = ALLOC_ACTION(perm);
288 perm_char = arg1[0]; 376 ap->perm_mask = xstrtol_range(arg1, 8, 0, 07777);
289 if (perm_char == '-') 377 ap->perm_char = arg1[0];
290 perm_mask = -perm_mask; 378 if (ap->perm_char == '-')
379 ap->perm_mask = -ap->perm_mask;
380 }
291#endif 381#endif
292#if ENABLE_FEATURE_FIND_MTIME 382#if ENABLE_FEATURE_FIND_MTIME
293 } else if (strcmp(arg, "-mtime") == 0) { 383 else if (strcmp(arg, "-mtime") == 0) {
384 action_mtime *ap;
294 if (++i == argc) 385 if (++i == argc)
295 bb_error_msg_and_die(bb_msg_requires_arg, arg); 386 bb_error_msg_and_die(bb_msg_requires_arg, arg);
296 mtime_days = xatol(arg1); 387 ap = ALLOC_ACTION(mtime);
297 mtime_char = arg1[0]; 388 ap->mtime_days = xatol(arg1);
298 if (mtime_char == '-') 389 ap->mtime_char = arg1[0];
299 mtime_days = -mtime_days; 390 if (ap->mtime_char == '-')
391 ap->mtime_days = -ap->mtime_days;
392 }
300#endif 393#endif
301#if ENABLE_FEATURE_FIND_MMIN 394#if ENABLE_FEATURE_FIND_MMIN
302 } else if (strcmp(arg, "-mmin") == 0) { 395 else if (strcmp(arg, "-mmin") == 0) {
396 action_mmin *ap;
303 if (++i == argc) 397 if (++i == argc)
304 bb_error_msg_and_die(bb_msg_requires_arg, arg); 398 bb_error_msg_and_die(bb_msg_requires_arg, arg);
305 mmin_mins = xatol(arg1); 399 ap = ALLOC_ACTION(mmin);
306 mmin_char = arg1[0]; 400 ap->mmin_mins = xatol(arg1);
307 if (mmin_char == '-') 401 ap->mmin_char = arg1[0];
308 mmin_mins = -mmin_mins; 402 if (ap->mmin_char == '-')
309#endif 403 ap->mmin_mins = -ap->mmin_mins;
310#if ENABLE_FEATURE_FIND_XDEV 404 }
311 } else if (strcmp(arg, "-xdev") == 0) {
312 struct stat stbuf;
313
314 xdev_count = (firstopt - 1) ? (firstopt - 1) : 1;
315 xdev_dev = xmalloc(xdev_count * sizeof(dev_t));
316
317 if (firstopt == 1) {
318 xstat(".", &stbuf);
319 xdev_dev[0] = stbuf.st_dev;
320 } else {
321 for (j = 1; j < firstopt; i++) {
322 xstat(argv[j], &stbuf);
323 xdev_dev[j-1] = stbuf.st_dev;
324 }
325 }
326#endif 405#endif
327#if ENABLE_FEATURE_FIND_NEWER 406#if ENABLE_FEATURE_FIND_NEWER
328 } else if (strcmp(arg, "-newer") == 0) { 407 else if (strcmp(arg, "-newer") == 0) {
408 action_newer *ap;
329 struct stat stat_newer; 409 struct stat stat_newer;
330 if (++i == argc) 410 if (++i == argc)
331 bb_error_msg_and_die(bb_msg_requires_arg, arg); 411 bb_error_msg_and_die(bb_msg_requires_arg, arg);
332 xstat(arg1, &stat_newer); 412 xstat(arg1, &stat_newer);
333 newer_mtime = stat_newer.st_mtime; 413 ap = ALLOC_ACTION(newer);
414 ap->newer_mtime = stat_newer.st_mtime;
415 }
334#endif 416#endif
335#if ENABLE_FEATURE_FIND_INUM 417#if ENABLE_FEATURE_FIND_INUM
336 } else if (strcmp(arg, "-inum") == 0) { 418 else if (strcmp(arg, "-inum") == 0) {
419 action_inum *ap;
337 if (++i == argc) 420 if (++i == argc)
338 bb_error_msg_and_die(bb_msg_requires_arg, arg); 421 bb_error_msg_and_die(bb_msg_requires_arg, arg);
339 inode_num = xatoul(arg1); 422 ap = ALLOC_ACTION(inum);
423 ap->inode_num = xatoul(arg1);
424 }
340#endif 425#endif
341#if ENABLE_FEATURE_FIND_EXEC 426#if ENABLE_FEATURE_FIND_EXEC
342 } else if (strcmp(arg, "-exec") == 0) { 427 else if (strcmp(arg, "-exec") == 0) {
428 action_exec *ap;
429 need_default = 0;
430 ap = ALLOC_ACTION(exec);
343 i++; /* now: argv[i] is the first arg after -exec */ 431 i++; /* now: argv[i] is the first arg after -exec */
344 exec_argv = &argv[i]; 432 ap->exec_argv = &argv[i];
345 exec_argc = i; 433 ap->exec_argc = i;
346 while (1) { 434 while (1) {
347 if (i == argc) /* did not see ';' till end */ 435 if (i == argc) /* did not see ';' till end */
348 bb_error_msg_and_die(bb_msg_requires_arg, arg); 436 bb_error_msg_and_die(bb_msg_requires_arg, arg);
@@ -350,23 +438,22 @@ int find_main(int argc, char **argv)
350 break; 438 break;
351 i++; 439 i++;
352 } 440 }
353 exec_argc = i - exec_argc; /* number of --exec arguments */ 441 ap->exec_argc = i - ap->exec_argc; /* number of --exec arguments */
354 if (exec_argc == 0) 442 if (ap->exec_argc == 0)
355 bb_error_msg_and_die(bb_msg_requires_arg, arg); 443 bb_error_msg_and_die(bb_msg_requires_arg, arg);
356 subst_count = xmalloc(exec_argc * sizeof(int)); 444 ap->subst_count = xmalloc(ap->exec_argc * sizeof(int));
357 j = exec_argc; 445 j = ap->exec_argc;
358 while (j--) 446 while (j--)
359 subst_count[j] = count_subst(exec_argv[j]); 447 ap->subst_count[j] = count_subst(ap->exec_argv[j]);
448 }
360#endif 449#endif
361 } else 450 else
362 bb_show_usage(); 451 bb_show_usage();
363 } 452 }
364 453
365 if (firstopt == 1) { 454 if (need_default)
366 static const char *const dot[] = { ".", NULL }; 455 (void) ALLOC_ACTION(print);
367 firstopt++; 456
368 argv = (char**)dot - 1;
369 }
370 for (i = 1; i < firstopt; i++) { 457 for (i = 1; i < firstopt; i++) {
371 if (!recursive_action(argv[i], 458 if (!recursive_action(argv[i],
372 TRUE, // recurse 459 TRUE, // recurse