blob: abd7576624dbaaedf1c9a676781df67bc409fbb2 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersen17d49ef1999-10-06 20:25:32 +00002/*
3 * Mini find implementation for busybox
4 *
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Eric Andersenc4996011999-10-20 22:08:37 +00006 *
Matt Kraai096370d2001-02-07 03:52:38 +00007 * Reworked by David Douthitt <n9ubh@callsign.net> and
8 * Matt Kraai <kraai@alumni.carnegiemellon.edu>.
Eric Andersen17d49ef1999-10-06 20:25:32 +00009 *
Rob Landleye9a7a622006-09-22 02:52:41 +000010 * Licensed under the GPL version 2, see the file LICENSE in this tarball.
Eric Andersen17d49ef1999-10-06 20:25:32 +000011 */
12
Denis Vlasenkodf0553b2006-10-29 00:21:47 +000013/* findutils-4.1.20:
14 *
15 * # find file.txt -exec 'echo {}' '{} {}' ';'
16 * find: echo file.txt: No such file or directory
17 * # find file.txt -exec 'echo' '{} {}' '; '
18 * find: missing argument to `-exec'
19 * # find file.txt -exec 'echo {}' '{} {}' ';' junk
20 * find: paths must precede expression
21 * # find file.txt -exec 'echo {}' '{} {}' ';' junk ';'
22 * find: paths must precede expression
23 * # find file.txt -exec 'echo' '{} {}' ';'
24 * file.txt file.txt
25 * (strace: execve("/bin/echo", ["echo", "file.txt file.txt"], [ 30 vars ]))
Denis Vlasenkodf0553b2006-10-29 00:21:47 +000026 * # find file.txt -exec 'echo' '{} {}' ';' -print -exec pwd ';'
27 * file.txt file.txt
28 * file.txt
29 * /tmp
Denis Vlasenkoe2fb7192006-10-29 19:03:56 +000030 * # find -name '*.c' -o -name '*.h'
31 * [shows files, *.c and *.h intermixed]
Denis Vlasenko5d499e12006-10-29 19:07:01 +000032 * # 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
Denis Vlasenkodf0553b2006-10-29 00:21:47 +000038 */
39
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000040#include "busybox.h"
Matt Kraai096370d2001-02-07 03:52:38 +000041#include <fnmatch.h>
Eric Andersen17d49ef1999-10-06 20:25:32 +000042
Denis Vlasenko5d499e12006-10-29 19:07:01 +000043USE_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
44USE_FEATURE_FIND_XDEV(static int xdev_count;)
Matt Kraai096370d2001-02-07 03:52:38 +000045
Denis Vlasenko5d499e12006-10-29 19:07:01 +000046typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *);
Matt Kraai096370d2001-02-07 03:52:38 +000047
Denis Vlasenko5d499e12006-10-29 19:07:01 +000048typedef struct {
49 action_fp f;
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;))
Matt Kraai096370d2001-02-07 03:52:38 +000063
Denis Vlasenko5d499e12006-10-29 19:07:01 +000064static action ***actions;
Eric Andersen17d49ef1999-10-06 20:25:32 +000065
Rob Landley5d3a0e82005-10-04 03:34:39 +000066
Denis Vlasenkodf0553b2006-10-29 00:21:47 +000067static int count_subst(const char *str)
68{
69 int count = 0;
70 while ((str = strstr(str, "{}"))) {
71 count++;
72 str++;
73 }
74 return count;
75}
76
77
78static char* subst(const char *src, int count, const char* filename)
79{
80 char *buf, *dst, *end;
81 int flen = strlen(filename);
Denis Vlasenkodf0553b2006-10-29 00:21:47 +000082 /* we replace each '{}' with filename: growth by strlen-2 */
83 buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1);
84 while ((end = strstr(src, "{}"))) {
85 memcpy(dst, src, end - src);
86 dst += end - src;
87 src = end + 2;
88 memcpy(dst, filename, flen);
89 dst += flen;
90 }
91 strcpy(dst, src);
Denis Vlasenkodf0553b2006-10-29 00:21:47 +000092 return buf;
93}
94
95
Denis Vlasenko5d499e12006-10-29 19:07:01 +000096SFUNC(name)
Eric Andersen17d49ef1999-10-06 20:25:32 +000097{
Denis Vlasenko5d499e12006-10-29 19:07:01 +000098 const char *tmp = strrchr(fileName, '/');
99 if (tmp == NULL)
100 tmp = fileName;
101 else
102 tmp++;
103 return fnmatch(ap->pattern, tmp, FNM_PERIOD) == 0;
104}
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000105#if ENABLE_FEATURE_FIND_TYPE
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000106SFUNC(type)
107{
108 return !((statbuf->st_mode & S_IFMT) == ap->type_mask);
109}
Rob Landleycee605c2005-10-06 16:39:17 +0000110#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000111#if ENABLE_FEATURE_FIND_PERM
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000112SFUNC(perm)
113{
114 return !((isdigit(ap->perm_char) && (statbuf->st_mode & 07777) == ap->perm_mask)
115 || (ap->perm_char == '-' && (statbuf->st_mode & ap->perm_mask) == ap->perm_mask)
116 || (ap->perm_char == '+' && (statbuf->st_mode & ap->perm_mask) != 0));
117}
Rob Landleycee605c2005-10-06 16:39:17 +0000118#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000119#if ENABLE_FEATURE_FIND_MTIME
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000120SFUNC(mtime)
121{
122 time_t file_age = time(NULL) - statbuf->st_mtime;
123 time_t mtime_secs = ap->mtime_days * 24 * 60 * 60;
124 return !((isdigit(ap->mtime_char) && file_age >= mtime_secs
125 && file_age < mtime_secs + 24 * 60 * 60)
126 || (ap->mtime_char == '+' && file_age >= mtime_secs + 24 * 60 * 60)
127 || (ap->mtime_char == '-' && file_age < mtime_secs));
128}
Rob Landleycee605c2005-10-06 16:39:17 +0000129#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000130#if ENABLE_FEATURE_FIND_MMIN
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000131SFUNC(mmin)
132{
133 time_t file_age = time(NULL) - statbuf->st_mtime;
134 time_t mmin_secs = ap->mmin_mins * 60;
135 return !((isdigit(ap->mmin_char) && file_age >= mmin_secs
136 && file_age < mmin_secs + 60)
137 || (ap->mmin_char == '+' && file_age >= mmin_secs + 60)
138 || (ap->mmin_char == '-' && file_age < mmin_secs));
139}
Paul Fox72d1a232006-01-13 21:05:41 +0000140#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000141#if ENABLE_FEATURE_FIND_NEWER
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000142SFUNC(newer)
143{
144 return (ap->newer_mtime >= statbuf->st_mtime);
145}
Rob Landleycee605c2005-10-06 16:39:17 +0000146#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000147#if ENABLE_FEATURE_FIND_INUM
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000148SFUNC(inum)
149{
150 return (statbuf->st_ino != ap->inode_num);
151}
Rob Landleycee605c2005-10-06 16:39:17 +0000152#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000153#if ENABLE_FEATURE_FIND_EXEC
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000154SFUNC(exec)
155{
156 int i, rc;
157 char *argv[ap->exec_argc+1];
158 for (i = 0; i < ap->exec_argc; i++)
159 argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName);
160 argv[i] = NULL; /* terminate the list */
161 errno = 0;
162 rc = wait4pid(spawn(argv));
163 if (errno)
164 bb_perror_msg("%s", argv[0]);
165 for (i = 0; i < ap->exec_argc; i++)
166 free(argv[i]);
167 return rc == 0; /* return 1 if success */
168}
Rob Landleycee605c2005-10-06 16:39:17 +0000169#endif
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000170
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000171#if ENABLE_FEATURE_FIND_PRINT0
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000172SFUNC(print0)
173{
174 printf("%s%c", fileName, '\0');
Denis Vlasenko3a6755f2006-10-14 14:24:30 +0000175 return TRUE;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000176}
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000177#endif
178SFUNC(print)
179{
180 puts(fileName);
181 return TRUE;
182}
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
Eric Andersen17d49ef1999-10-06 20:25:32 +0000205
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000206#if ENABLE_FEATURE_FIND_TYPE
Matt Kraai096370d2001-02-07 03:52:38 +0000207static int find_type(char *type)
208{
209 int mask = 0;
210
211 switch (type[0]) {
Denis Vlasenko3a6755f2006-10-14 14:24:30 +0000212 case 'b':
213 mask = S_IFBLK;
214 break;
215 case 'c':
216 mask = S_IFCHR;
217 break;
218 case 'd':
219 mask = S_IFDIR;
220 break;
221 case 'p':
222 mask = S_IFIFO;
223 break;
224 case 'f':
225 mask = S_IFREG;
226 break;
227 case 'l':
228 mask = S_IFLNK;
229 break;
230 case 's':
231 mask = S_IFSOCK;
232 break;
Matt Kraai096370d2001-02-07 03:52:38 +0000233 }
234
235 if (mask == 0 || type[1] != '\0')
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000236 bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
Matt Kraai096370d2001-02-07 03:52:38 +0000237
238 return mask;
239}
240#endif
241
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000242
Eric Andersen17d49ef1999-10-06 20:25:32 +0000243int find_main(int argc, char **argv)
244{
Matt Kraai096370d2001-02-07 03:52:38 +0000245 int dereference = FALSE;
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000246 int i, j, firstopt, status = EXIT_SUCCESS;
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000247 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)
Eric Andersen17d49ef1999-10-06 20:25:32 +0000261
Matt Kraai096370d2001-02-07 03:52:38 +0000262 for (firstopt = 1; firstopt < argc; firstopt++) {
263 if (argv[firstopt][0] == '-')
264 break;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000265 }
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000266 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 */
Eric Andersen17d49ef1999-10-06 20:25:32 +0000295
Erik Andersene49d5ec2000-02-08 19:58:47 +0000296 /* Parse any options */
Matt Kraai096370d2001-02-07 03:52:38 +0000297 for (i = firstopt; i < argc; i++) {
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000298 char *arg = argv[i];
299 char *arg1 = argv[i+1];
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000300
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)
Matt Kraai096370d2001-02-07 03:52:38 +0000322 dereference = TRUE;
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000323#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 --- */
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000338 else if (strcmp(arg, "-print") == 0) {
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000339 need_default = 0;
340 (void) ALLOC_ACTION(print);
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000341 }
342#if ENABLE_FEATURE_FIND_PRINT0
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000343 else if (strcmp(arg, "-print0") == 0) {
344 need_default = 0;
345 (void) ALLOC_ACTION(print0);
346 }
Paul Foxd7384292006-05-12 14:47:20 +0000347#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000348 else if (strcmp(arg, "-name") == 0) {
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000349 action_name *ap;
Matt Kraai096370d2001-02-07 03:52:38 +0000350 if (++i == argc)
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000351 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000352 ap = ALLOC_ACTION(name);
353 ap->pattern = arg1;
354 }
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000355#if ENABLE_FEATURE_FIND_TYPE
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000356 else if (strcmp(arg, "-type") == 0) {
357 action_type *ap;
Matt Kraai096370d2001-02-07 03:52:38 +0000358 if (++i == argc)
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000359 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000360 ap = ALLOC_ACTION(type);
361 ap->type_mask = find_type(arg1);
362 }
Rob Landleycee605c2005-10-06 16:39:17 +0000363#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000364#if ENABLE_FEATURE_FIND_PERM
365/* TODO:
366 * -perm mode File's permission bits are exactly mode (octal or symbolic).
367 * Symbolic modes use mode 0 as a point of departure.
368 * -perm -mode All of the permission bits mode are set for the file.
369 * -perm +mode Any of the permission bits mode are set for the file.
370 */
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000371 else if (strcmp(arg, "-perm") == 0) {
372 action_perm *ap;
Matt Kraai096370d2001-02-07 03:52:38 +0000373 if (++i == argc)
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000374 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000375 ap = ALLOC_ACTION(perm);
376 ap->perm_mask = xstrtol_range(arg1, 8, 0, 07777);
377 ap->perm_char = arg1[0];
378 if (ap->perm_char == '-')
379 ap->perm_mask = -ap->perm_mask;
380 }
Rob Landleycee605c2005-10-06 16:39:17 +0000381#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000382#if ENABLE_FEATURE_FIND_MTIME
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000383 else if (strcmp(arg, "-mtime") == 0) {
384 action_mtime *ap;
Matt Kraai096370d2001-02-07 03:52:38 +0000385 if (++i == argc)
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000386 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000387 ap = ALLOC_ACTION(mtime);
388 ap->mtime_days = xatol(arg1);
389 ap->mtime_char = arg1[0];
390 if (ap->mtime_char == '-')
391 ap->mtime_days = -ap->mtime_days;
392 }
Rob Landleycee605c2005-10-06 16:39:17 +0000393#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000394#if ENABLE_FEATURE_FIND_MMIN
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000395 else if (strcmp(arg, "-mmin") == 0) {
396 action_mmin *ap;
Paul Fox72d1a232006-01-13 21:05:41 +0000397 if (++i == argc)
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000398 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000399 ap = ALLOC_ACTION(mmin);
400 ap->mmin_mins = xatol(arg1);
401 ap->mmin_char = arg1[0];
402 if (ap->mmin_char == '-')
403 ap->mmin_mins = -ap->mmin_mins;
404 }
Rob Landleycee605c2005-10-06 16:39:17 +0000405#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000406#if ENABLE_FEATURE_FIND_NEWER
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000407 else if (strcmp(arg, "-newer") == 0) {
408 action_newer *ap;
Eric Andersen97d86f22003-01-23 05:27:42 +0000409 struct stat stat_newer;
410 if (++i == argc)
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000411 bb_error_msg_and_die(bb_msg_requires_arg, arg);
412 xstat(arg1, &stat_newer);
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000413 ap = ALLOC_ACTION(newer);
414 ap->newer_mtime = stat_newer.st_mtime;
415 }
Rob Landleycee605c2005-10-06 16:39:17 +0000416#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000417#if ENABLE_FEATURE_FIND_INUM
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000418 else if (strcmp(arg, "-inum") == 0) {
419 action_inum *ap;
Eric Andersen97d86f22003-01-23 05:27:42 +0000420 if (++i == argc)
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000421 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000422 ap = ALLOC_ACTION(inum);
423 ap->inode_num = xatoul(arg1);
424 }
Rob Landleycee605c2005-10-06 16:39:17 +0000425#endif
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000426#if ENABLE_FEATURE_FIND_EXEC
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000427 else if (strcmp(arg, "-exec") == 0) {
428 action_exec *ap;
429 need_default = 0;
430 ap = ALLOC_ACTION(exec);
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000431 i++; /* now: argv[i] is the first arg after -exec */
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000432 ap->exec_argv = &argv[i];
433 ap->exec_argc = i;
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000434 while (1) {
435 if (i == argc) /* did not see ';' till end */
436 bb_error_msg_and_die(bb_msg_requires_arg, arg);
437 if (argv[i][0] == ';' && argv[i][1] == '\0')
Rob Landley5d3a0e82005-10-04 03:34:39 +0000438 break;
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000439 i++;
Rob Landley5d3a0e82005-10-04 03:34:39 +0000440 }
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000441 ap->exec_argc = i - ap->exec_argc; /* number of --exec arguments */
442 if (ap->exec_argc == 0)
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000443 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000444 ap->subst_count = xmalloc(ap->exec_argc * sizeof(int));
445 j = ap->exec_argc;
Denis Vlasenkodf0553b2006-10-29 00:21:47 +0000446 while (j--)
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000447 ap->subst_count[j] = count_subst(ap->exec_argv[j]);
448 }
Rob Landleycee605c2005-10-06 16:39:17 +0000449#endif
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000450 else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000451 bb_show_usage();
Erik Andersene49d5ec2000-02-08 19:58:47 +0000452 }
453
Denis Vlasenko5d499e12006-10-29 19:07:01 +0000454 if (need_default)
455 (void) ALLOC_ACTION(print);
456
Denis Vlasenkoe2fb7192006-10-29 19:03:56 +0000457 for (i = 1; i < firstopt; i++) {
458 if (!recursive_action(argv[i],
459 TRUE, // recurse
460 dereference, // follow links
461 FALSE, // depth first
462 fileAction, // file action
463 fileAction, // dir action
464 NULL, // user data
465 0)) // depth
466 status = EXIT_FAILURE;
467 }
Matt Kraai096370d2001-02-07 03:52:38 +0000468 return status;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000469}