1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329#include <fnmatch.h>
330#include "libbb.h"
331#if ENABLE_FEATURE_FIND_REGEX
332# include "xregex.h"
333#endif
334
335#ifndef FNM_CASEFOLD
336# define FNM_CASEFOLD 0
337#endif
338
339#define dbg(...) ((void)0)
340
341
342
343
344
345typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC;
346
347typedef struct {
348 action_fp f;
349#if ENABLE_FEATURE_FIND_NOT
350 bool invert;
351#endif
352} action;
353
354#define ACTS(name, ...) typedef struct { action a; __VA_ARGS__ } action_##name;
355#define ACTF(name) \
356 static int FAST_FUNC func_##name(const char *fileName UNUSED_PARAM, \
357 const struct stat *statbuf UNUSED_PARAM, \
358 action_##name* ap UNUSED_PARAM)
359
360 ACTS(print)
361 ACTS(name, const char *pattern; bool iname;)
362IF_FEATURE_FIND_PATH( ACTS(path, const char *pattern; bool ipath;))
363IF_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;))
364IF_FEATURE_FIND_PRINT0( ACTS(print0))
365IF_FEATURE_FIND_TYPE( ACTS(type, int type_mask;))
366IF_FEATURE_FIND_PERM( ACTS(perm, char perm_char; mode_t perm_mask;))
367IF_FEATURE_FIND_MTIME( ACTS(mtime, char mtime_char; unsigned mtime_days;))
368IF_FEATURE_FIND_MMIN( ACTS(mmin, char mmin_char; unsigned mmin_mins;))
369IF_FEATURE_FIND_NEWER( ACTS(newer, time_t newer_mtime;))
370IF_FEATURE_FIND_INUM( ACTS(inum, ino_t inode_num;))
371IF_FEATURE_FIND_USER( ACTS(user, uid_t uid;))
372IF_FEATURE_FIND_SIZE( ACTS(size, char size_char; off_t size;))
373IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;))
374IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;))
375IF_FEATURE_FIND_PRUNE( ACTS(prune))
376IF_FEATURE_FIND_DELETE( ACTS(delete))
377IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;))
378IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;))
379IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;))
380
381struct globals {
382 IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;)
383 IF_FEATURE_FIND_XDEV(int xdev_count;)
384#if ENABLE_FEATURE_FIND_MAXDEPTH
385 int minmaxdepth[2];
386#endif
387 action ***actions;
388 smallint need_print;
389 smallint xdev_on;
390 recurse_flags_t recurse_flags;
391} FIX_ALIASING;
392#define G (*(struct globals*)&bb_common_bufsiz1)
393#define INIT_G() do { \
394 struct G_sizecheck { \
395 char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
396 }; \
397 \
398 memset(&G, 0, sizeof(G)); \
399 IF_FEATURE_FIND_MAXDEPTH(G.minmaxdepth[1] = INT_MAX;) \
400 G.need_print = 1; \
401 G.recurse_flags = ACTION_RECURSE; \
402} while (0)
403
404#if ENABLE_FEATURE_FIND_EXEC
405static unsigned count_subst(const char *str)
406{
407 unsigned count = 0;
408 while ((str = strstr(str, "{}")) != NULL) {
409 count++;
410 str++;
411 }
412 return count;
413}
414
415
416static char* subst(const char *src, unsigned count, const char* filename)
417{
418 char *buf, *dst, *end;
419 size_t flen = strlen(filename);
420
421 buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1);
422 while ((end = strstr(src, "{}"))) {
423 memcpy(dst, src, end - src);
424 dst += end - src;
425 src = end + 2;
426 memcpy(dst, filename, flen);
427 dst += flen;
428 }
429 strcpy(dst, src);
430 return buf;
431}
432#endif
433
434
435
436
437
438
439static int exec_actions(action ***appp, const char *fileName, const struct stat *statbuf)
440{
441 int cur_group;
442 int cur_action;
443 int rc = 0;
444 action **app, *ap;
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463 cur_group = -1;
464 while ((app = appp[++cur_group]) != NULL) {
465 rc &= ~TRUE;
466 cur_action = -1;
467 while (1) {
468 ap = app[++cur_action];
469 if (!ap)
470 return rc ^ TRUE;
471 rc |= TRUE ^ ap->f(fileName, statbuf, ap);
472#if ENABLE_FEATURE_FIND_NOT
473 if (ap->invert) rc ^= TRUE;
474#endif
475 dbg("grp %d action %d rc:0x%x", cur_group, cur_action, rc);
476 if (rc & TRUE)
477 break;
478 }
479 }
480 dbg("returning:0x%x", rc ^ TRUE);
481 return rc ^ TRUE;
482}
483
484
485#if !FNM_CASEFOLD
486static char *strcpy_upcase(char *dst, const char *src)
487{
488 char *d = dst;
489 while (1) {
490 unsigned char ch = *src++;
491 if (ch >= 'a' && ch <= 'z')
492 ch -= ('a' - 'A');
493 *d++ = ch;
494 if (ch == '\0')
495 break;
496 }
497 return dst;
498}
499#endif
500
501ACTF(name)
502{
503 const char *tmp = bb_basename(fileName);
504 if (tmp != fileName && *tmp == '\0') {
505
506 tmp--;
507 while (tmp != fileName && *--tmp != '/')
508 continue;
509 if (*tmp == '/')
510 tmp++;
511 }
512
513
514
515
516#if FNM_CASEFOLD
517 return fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)) == 0;
518#else
519 if (ap->iname)
520 tmp = strcpy_upcase(alloca(strlen(tmp) + 1), tmp);
521 return fnmatch(ap->pattern, tmp, 0) == 0;
522#endif
523}
524
525#if ENABLE_FEATURE_FIND_PATH
526ACTF(path)
527{
528# if FNM_CASEFOLD
529 return fnmatch(ap->pattern, fileName, (ap->ipath ? FNM_CASEFOLD : 0)) == 0;
530# else
531 if (ap->ipath)
532 fileName = strcpy_upcase(alloca(strlen(fileName) + 1), fileName);
533 return fnmatch(ap->pattern, fileName, 0) == 0;
534# endif
535}
536#endif
537#if ENABLE_FEATURE_FIND_REGEX
538ACTF(regex)
539{
540 regmatch_t match;
541 if (regexec(&ap->compiled_pattern, fileName, 1, &match, 0 ))
542 return 0;
543 if (match.rm_so)
544 return 0;
545 if (fileName[match.rm_eo])
546 return 0;
547 return 1;
548}
549#endif
550#if ENABLE_FEATURE_FIND_TYPE
551ACTF(type)
552{
553 return ((statbuf->st_mode & S_IFMT) == ap->type_mask);
554}
555#endif
556#if ENABLE_FEATURE_FIND_PERM
557ACTF(perm)
558{
559
560 if (ap->perm_char == '+')
561 return (statbuf->st_mode & ap->perm_mask) != 0;
562
563 if (ap->perm_char == '-')
564 return (statbuf->st_mode & ap->perm_mask) == ap->perm_mask;
565
566 return (statbuf->st_mode & 07777) == ap->perm_mask;
567}
568#endif
569#if ENABLE_FEATURE_FIND_MTIME
570ACTF(mtime)
571{
572 time_t file_age = time(NULL) - statbuf->st_mtime;
573 time_t mtime_secs = ap->mtime_days * 24*60*60;
574 if (ap->mtime_char == '+')
575 return file_age >= mtime_secs + 24*60*60;
576 if (ap->mtime_char == '-')
577 return file_age < mtime_secs;
578
579 return file_age >= mtime_secs && file_age < (mtime_secs + 24*60*60);
580}
581#endif
582#if ENABLE_FEATURE_FIND_MMIN
583ACTF(mmin)
584{
585 time_t file_age = time(NULL) - statbuf->st_mtime;
586 time_t mmin_secs = ap->mmin_mins * 60;
587 if (ap->mmin_char == '+')
588 return file_age >= mmin_secs + 60;
589 if (ap->mmin_char == '-')
590 return file_age < mmin_secs;
591
592 return file_age >= mmin_secs && file_age < (mmin_secs + 60);
593}
594#endif
595#if ENABLE_FEATURE_FIND_NEWER
596ACTF(newer)
597{
598 return (ap->newer_mtime < statbuf->st_mtime);
599}
600#endif
601#if ENABLE_FEATURE_FIND_INUM
602ACTF(inum)
603{
604 return (statbuf->st_ino == ap->inode_num);
605}
606#endif
607#if ENABLE_FEATURE_FIND_EXEC
608ACTF(exec)
609{
610 int i, rc;
611#if ENABLE_USE_PORTABLE_CODE
612 char **argv = alloca(sizeof(char*) * (ap->exec_argc + 1));
613#else
614 char *argv[ap->exec_argc + 1];
615#endif
616 for (i = 0; i < ap->exec_argc; i++)
617 argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName);
618 argv[i] = NULL;
619
620 rc = spawn_and_wait(argv);
621 if (rc < 0)
622 bb_simple_perror_msg(argv[0]);
623
624 i = 0;
625 while (argv[i])
626 free(argv[i++]);
627 return rc == 0;
628}
629#endif
630#if ENABLE_FEATURE_FIND_USER
631ACTF(user)
632{
633 return (statbuf->st_uid == ap->uid);
634}
635#endif
636#if ENABLE_FEATURE_FIND_GROUP
637ACTF(group)
638{
639 return (statbuf->st_gid == ap->gid);
640}
641#endif
642#if ENABLE_FEATURE_FIND_PRINT0
643ACTF(print0)
644{
645 printf("%s%c", fileName, '\0');
646 return TRUE;
647}
648#endif
649ACTF(print)
650{
651 puts(fileName);
652 return TRUE;
653}
654#if ENABLE_FEATURE_FIND_PAREN
655ACTF(paren)
656{
657 return exec_actions(ap->subexpr, fileName, statbuf);
658}
659#endif
660#if ENABLE_FEATURE_FIND_SIZE
661ACTF(size)
662{
663 if (ap->size_char == '+')
664 return statbuf->st_size > ap->size;
665 if (ap->size_char == '-')
666 return statbuf->st_size < ap->size;
667 return statbuf->st_size == ap->size;
668}
669#endif
670#if ENABLE_FEATURE_FIND_PRUNE
671
672
673
674
675
676
677ACTF(prune)
678{
679 return SKIP + TRUE;
680}
681#endif
682#if ENABLE_FEATURE_FIND_DELETE
683ACTF(delete)
684{
685 int rc;
686 if (S_ISDIR(statbuf->st_mode)) {
687 rc = rmdir(fileName);
688 } else {
689 rc = unlink(fileName);
690 }
691 if (rc < 0)
692 bb_simple_perror_msg(fileName);
693 return TRUE;
694}
695#endif
696#if ENABLE_FEATURE_FIND_CONTEXT
697ACTF(context)
698{
699 security_context_t con;
700 int rc;
701
702 if (G.recurse_flags & ACTION_FOLLOWLINKS) {
703 rc = getfilecon(fileName, &con);
704 } else {
705 rc = lgetfilecon(fileName, &con);
706 }
707 if (rc < 0)
708 return FALSE;
709 rc = strcmp(ap->context, con);
710 freecon(con);
711 return rc == 0;
712}
713#endif
714#if ENABLE_FEATURE_FIND_LINKS
715ACTF(links)
716{
717 switch(ap->links_char) {
718 case '-' : return (statbuf->st_nlink < ap->links_count);
719 case '+' : return (statbuf->st_nlink > ap->links_count);
720 default: return (statbuf->st_nlink == ap->links_count);
721 }
722}
723#endif
724
725static int FAST_FUNC fileAction(const char *fileName,
726 struct stat *statbuf,
727 void *userData UNUSED_PARAM,
728 int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM))
729{
730 int r;
731
732#if ENABLE_FEATURE_FIND_MAXDEPTH
733 if (depth < G.minmaxdepth[0])
734 return TRUE;
735 if (depth > G.minmaxdepth[1])
736 return SKIP;
737#endif
738
739 r = exec_actions(G.actions, fileName, statbuf);
740
741 if ((r & TRUE) && G.need_print)
742 puts(fileName);
743
744#if ENABLE_FEATURE_FIND_MAXDEPTH
745 if (S_ISDIR(statbuf->st_mode)) {
746 if (depth == G.minmaxdepth[1])
747 return SKIP;
748 }
749#endif
750#if ENABLE_FEATURE_FIND_XDEV
751
752
753 if (S_ISDIR(statbuf->st_mode)) {
754 if (G.xdev_count) {
755 int i;
756 for (i = 0; i < G.xdev_count; i++) {
757 if (G.xdev_dev[i] == statbuf->st_dev)
758 goto found;
759 }
760 return SKIP;
761 found: ;
762 }
763 }
764#endif
765
766
767
768 return (r & SKIP) ? SKIP : TRUE;
769}
770
771
772#if ENABLE_FEATURE_FIND_TYPE
773static int find_type(const char *type)
774{
775 int mask = 0;
776
777 if (*type == 'b')
778 mask = S_IFBLK;
779 else if (*type == 'c')
780 mask = S_IFCHR;
781 else if (*type == 'd')
782 mask = S_IFDIR;
783 else if (*type == 'p')
784 mask = S_IFIFO;
785 else if (*type == 'f')
786 mask = S_IFREG;
787 else if (*type == 'l')
788 mask = S_IFLNK;
789 else if (*type == 's')
790 mask = S_IFSOCK;
791
792 if (mask == 0 || type[1] != '\0')
793 bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
794
795 return mask;
796}
797#endif
798
799#if ENABLE_FEATURE_FIND_PERM \
800 || ENABLE_FEATURE_FIND_MTIME || ENABLE_FEATURE_FIND_MMIN \
801 || ENABLE_FEATURE_FIND_SIZE || ENABLE_FEATURE_FIND_LINKS
802static const char* plus_minus_num(const char* str)
803{
804 if (*str == '-' || *str == '+')
805 str++;
806 return str;
807}
808#endif
809
810static action*** parse_params(char **argv)
811{
812 enum {
813 OPT_FOLLOW ,
814 IF_FEATURE_FIND_XDEV( OPT_XDEV ,)
815 IF_FEATURE_FIND_DEPTH( OPT_DEPTH ,)
816 PARM_a ,
817 PARM_o ,
818 IF_FEATURE_FIND_NOT( PARM_char_not ,)
819#if ENABLE_DESKTOP
820 PARM_and ,
821 PARM_or ,
822 IF_FEATURE_FIND_NOT( PARM_not ,)
823#endif
824 PARM_print ,
825 IF_FEATURE_FIND_PRINT0( PARM_print0 ,)
826 IF_FEATURE_FIND_PRUNE( PARM_prune ,)
827 IF_FEATURE_FIND_DELETE( PARM_delete ,)
828 IF_FEATURE_FIND_EXEC( PARM_exec ,)
829 IF_FEATURE_FIND_PAREN( PARM_char_brace,)
830
831 PARM_name ,
832 PARM_iname ,
833 IF_FEATURE_FIND_PATH( PARM_path ,)
834#if ENABLE_DESKTOP
835
836
837 IF_FEATURE_FIND_PATH( PARM_wholename ,)
838#endif
839 IF_FEATURE_FIND_PATH( PARM_ipath ,)
840 IF_FEATURE_FIND_REGEX( PARM_regex ,)
841 IF_FEATURE_FIND_TYPE( PARM_type ,)
842 IF_FEATURE_FIND_PERM( PARM_perm ,)
843 IF_FEATURE_FIND_MTIME( PARM_mtime ,)
844 IF_FEATURE_FIND_MMIN( PARM_mmin ,)
845 IF_FEATURE_FIND_NEWER( PARM_newer ,)
846 IF_FEATURE_FIND_INUM( PARM_inum ,)
847 IF_FEATURE_FIND_USER( PARM_user ,)
848 IF_FEATURE_FIND_GROUP( PARM_group ,)
849 IF_FEATURE_FIND_SIZE( PARM_size ,)
850 IF_FEATURE_FIND_CONTEXT(PARM_context ,)
851 IF_FEATURE_FIND_LINKS( PARM_links ,)
852 IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,OPT_MAXDEPTH,)
853 };
854
855 static const char params[] ALIGN1 =
856 "-follow\0"
857 IF_FEATURE_FIND_XDEV( "-xdev\0" )
858 IF_FEATURE_FIND_DEPTH( "-depth\0" )
859 "-a\0"
860 "-o\0"
861 IF_FEATURE_FIND_NOT( "!\0" )
862#if ENABLE_DESKTOP
863 "-and\0"
864 "-or\0"
865 IF_FEATURE_FIND_NOT( "-not\0" )
866#endif
867 "-print\0"
868 IF_FEATURE_FIND_PRINT0( "-print0\0" )
869 IF_FEATURE_FIND_PRUNE( "-prune\0" )
870 IF_FEATURE_FIND_DELETE( "-delete\0" )
871 IF_FEATURE_FIND_EXEC( "-exec\0" )
872 IF_FEATURE_FIND_PAREN( "(\0" )
873
874 "-name\0"
875 "-iname\0"
876 IF_FEATURE_FIND_PATH( "-path\0" )
877#if ENABLE_DESKTOP
878 IF_FEATURE_FIND_PATH( "-wholename\0")
879#endif
880 IF_FEATURE_FIND_PATH( "-ipath\0" )
881 IF_FEATURE_FIND_REGEX( "-regex\0" )
882 IF_FEATURE_FIND_TYPE( "-type\0" )
883 IF_FEATURE_FIND_PERM( "-perm\0" )
884 IF_FEATURE_FIND_MTIME( "-mtime\0" )
885 IF_FEATURE_FIND_MMIN( "-mmin\0" )
886 IF_FEATURE_FIND_NEWER( "-newer\0" )
887 IF_FEATURE_FIND_INUM( "-inum\0" )
888 IF_FEATURE_FIND_USER( "-user\0" )
889 IF_FEATURE_FIND_GROUP( "-group\0" )
890 IF_FEATURE_FIND_SIZE( "-size\0" )
891 IF_FEATURE_FIND_CONTEXT("-context\0")
892 IF_FEATURE_FIND_LINKS( "-links\0" )
893 IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0")
894 ;
895
896 action*** appp;
897 unsigned cur_group = 0;
898 unsigned cur_action = 0;
899 IF_FEATURE_FIND_NOT( bool invert_flag = 0; )
900
901
902
903
904 auto action* alloc_action(int sizeof_struct, action_fp f);
905 action* alloc_action(int sizeof_struct, action_fp f)
906 {
907 action *ap;
908 appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(*appp));
909 appp[cur_group][cur_action++] = ap = xzalloc(sizeof_struct);
910 appp[cur_group][cur_action] = NULL;
911 ap->f = f;
912 IF_FEATURE_FIND_NOT( ap->invert = invert_flag; )
913 IF_FEATURE_FIND_NOT( invert_flag = 0; )
914 return ap;
915 }
916
917#define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name)
918
919 appp = xzalloc(2 * sizeof(appp[0]));
920
921 while (*argv) {
922 const char *arg = argv[0];
923 int parm = index_in_strings(params, arg);
924 const char *arg1 = argv[1];
925
926 dbg("arg:'%s' arg1:'%s' parm:%d PARM_type:%d", arg, arg1, parm, PARM_type);
927
928 if (parm >= PARM_name) {
929
930 if (!arg1)
931 bb_error_msg_and_die(bb_msg_requires_arg, arg);
932 argv++;
933 }
934
935
936
937
938
939
940
941
942
943 if (parm == OPT_FOLLOW) {
944 dbg("follow enabled: %d", __LINE__);
945 G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
946 }
947#if ENABLE_FEATURE_FIND_XDEV
948 else if (parm == OPT_XDEV) {
949 dbg("%d", __LINE__);
950 G.xdev_on = 1;
951 }
952#endif
953#if ENABLE_FEATURE_FIND_MAXDEPTH
954 else if (parm == OPT_MINDEPTH || parm == OPT_MINDEPTH + 1) {
955 dbg("%d", __LINE__);
956 G.minmaxdepth[parm - OPT_MINDEPTH] = xatoi_positive(arg1);
957 }
958#endif
959#if ENABLE_FEATURE_FIND_DEPTH
960 else if (parm == OPT_DEPTH) {
961 dbg("%d", __LINE__);
962 G.recurse_flags |= ACTION_DEPTHFIRST;
963 }
964#endif
965
966
967
968
969
970
971
972
973
974
975 else if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) {
976 dbg("%d", __LINE__);
977
978 }
979 else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) {
980 dbg("%d", __LINE__);
981
982 cur_group++;
983 appp = xrealloc(appp, (cur_group+2) * sizeof(*appp));
984
985 appp[cur_group+1] = NULL;
986 cur_action = 0;
987 }
988#if ENABLE_FEATURE_FIND_NOT
989 else if (parm == PARM_char_not IF_DESKTOP(|| parm == PARM_not)) {
990
991 invert_flag ^= 1;
992 dbg("invert_flag:%d", invert_flag);
993 }
994#endif
995
996 else if (parm == PARM_print) {
997 dbg("%d", __LINE__);
998 G.need_print = 0;
999 (void) ALLOC_ACTION(print);
1000 }
1001#if ENABLE_FEATURE_FIND_PRINT0
1002 else if (parm == PARM_print0) {
1003 dbg("%d", __LINE__);
1004 G.need_print = 0;
1005 (void) ALLOC_ACTION(print0);
1006 }
1007#endif
1008#if ENABLE_FEATURE_FIND_PRUNE
1009 else if (parm == PARM_prune) {
1010 dbg("%d", __LINE__);
1011 (void) ALLOC_ACTION(prune);
1012 }
1013#endif
1014#if ENABLE_FEATURE_FIND_DELETE
1015 else if (parm == PARM_delete) {
1016 dbg("%d", __LINE__);
1017 G.need_print = 0;
1018 G.recurse_flags |= ACTION_DEPTHFIRST;
1019 (void) ALLOC_ACTION(delete);
1020 }
1021#endif
1022#if ENABLE_FEATURE_FIND_EXEC
1023 else if (parm == PARM_exec) {
1024 int i;
1025 action_exec *ap;
1026 dbg("%d", __LINE__);
1027 G.need_print = 0;
1028 ap = ALLOC_ACTION(exec);
1029 ap->exec_argv = ++argv;
1030
1031 while (1) {
1032 if (!*argv)
1033 bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
1034
1035
1036
1037
1038
1039 if ((argv[0][0] == ';' || argv[0][0] == '+')
1040 && argv[0][1] == '\0'
1041 ) {
1042 break;
1043 }
1044 argv++;
1045 ap->exec_argc++;
1046 }
1047 if (ap->exec_argc == 0)
1048 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1049 ap->subst_count = xmalloc(ap->exec_argc * sizeof(int));
1050 i = ap->exec_argc;
1051 while (i--)
1052 ap->subst_count[i] = count_subst(ap->exec_argv[i]);
1053 }
1054#endif
1055#if ENABLE_FEATURE_FIND_PAREN
1056 else if (parm == PARM_char_brace) {
1057 action_paren *ap;
1058 char **endarg;
1059 unsigned nested = 1;
1060
1061 dbg("%d", __LINE__);
1062 endarg = argv;
1063 while (1) {
1064 if (!*++endarg)
1065 bb_error_msg_and_die("unpaired '('");
1066 if (LONE_CHAR(*endarg, '('))
1067 nested++;
1068 else if (LONE_CHAR(*endarg, ')') && !--nested) {
1069 *endarg = NULL;
1070 break;
1071 }
1072 }
1073 ap = ALLOC_ACTION(paren);
1074 ap->subexpr = parse_params(argv + 1);
1075 *endarg = (char*) ")";
1076 argv = endarg;
1077 }
1078#endif
1079 else if (parm == PARM_name || parm == PARM_iname) {
1080 action_name *ap;
1081 dbg("%d", __LINE__);
1082 ap = ALLOC_ACTION(name);
1083 ap->pattern = arg1;
1084 ap->iname = (parm == PARM_iname);
1085 }
1086#if ENABLE_FEATURE_FIND_PATH
1087 else if (parm == PARM_path IF_DESKTOP(|| parm == PARM_wholename) || parm == PARM_ipath) {
1088 action_path *ap;
1089 dbg("%d", __LINE__);
1090 ap = ALLOC_ACTION(path);
1091 ap->pattern = arg1;
1092 ap->ipath = (parm == PARM_ipath);
1093 }
1094#endif
1095#if ENABLE_FEATURE_FIND_REGEX
1096 else if (parm == PARM_regex) {
1097 action_regex *ap;
1098 dbg("%d", __LINE__);
1099 ap = ALLOC_ACTION(regex);
1100 xregcomp(&ap->compiled_pattern, arg1, 0 );
1101 }
1102#endif
1103#if ENABLE_FEATURE_FIND_TYPE
1104 else if (parm == PARM_type) {
1105 action_type *ap;
1106 ap = ALLOC_ACTION(type);
1107 ap->type_mask = find_type(arg1);
1108 dbg("created:type mask:%x", ap->type_mask);
1109 }
1110#endif
1111#if ENABLE_FEATURE_FIND_PERM
1112
1113
1114
1115
1116
1117 else if (parm == PARM_perm) {
1118 action_perm *ap;
1119 dbg("%d", __LINE__);
1120 ap = ALLOC_ACTION(perm);
1121 ap->perm_char = arg1[0];
1122 arg1 = plus_minus_num(arg1);
1123
1124 if (!bb_parse_mode(arg1, &ap->perm_mask))
1125 bb_error_msg_and_die("invalid mode '%s'", arg1);
1126 }
1127#endif
1128#if ENABLE_FEATURE_FIND_MTIME
1129 else if (parm == PARM_mtime) {
1130 action_mtime *ap;
1131 dbg("%d", __LINE__);
1132 ap = ALLOC_ACTION(mtime);
1133 ap->mtime_char = arg1[0];
1134 ap->mtime_days = xatoul(plus_minus_num(arg1));
1135 }
1136#endif
1137#if ENABLE_FEATURE_FIND_MMIN
1138 else if (parm == PARM_mmin) {
1139 action_mmin *ap;
1140 dbg("%d", __LINE__);
1141 ap = ALLOC_ACTION(mmin);
1142 ap->mmin_char = arg1[0];
1143 ap->mmin_mins = xatoul(plus_minus_num(arg1));
1144 }
1145#endif
1146#if ENABLE_FEATURE_FIND_NEWER
1147 else if (parm == PARM_newer) {
1148 struct stat stat_newer;
1149 action_newer *ap;
1150 dbg("%d", __LINE__);
1151 ap = ALLOC_ACTION(newer);
1152 xstat(arg1, &stat_newer);
1153 ap->newer_mtime = stat_newer.st_mtime;
1154 }
1155#endif
1156#if ENABLE_FEATURE_FIND_INUM
1157 else if (parm == PARM_inum) {
1158 action_inum *ap;
1159 dbg("%d", __LINE__);
1160 ap = ALLOC_ACTION(inum);
1161 ap->inode_num = xatoul(arg1);
1162 }
1163#endif
1164#if ENABLE_FEATURE_FIND_USER
1165 else if (parm == PARM_user) {
1166 action_user *ap;
1167 dbg("%d", __LINE__);
1168 ap = ALLOC_ACTION(user);
1169 ap->uid = bb_strtou(arg1, NULL, 10);
1170 if (errno)
1171 ap->uid = xuname2uid(arg1);
1172 }
1173#endif
1174#if ENABLE_FEATURE_FIND_GROUP
1175 else if (parm == PARM_group) {
1176 action_group *ap;
1177 dbg("%d", __LINE__);
1178 ap = ALLOC_ACTION(group);
1179 ap->gid = bb_strtou(arg1, NULL, 10);
1180 if (errno)
1181 ap->gid = xgroup2gid(arg1);
1182 }
1183#endif
1184#if ENABLE_FEATURE_FIND_SIZE
1185 else if (parm == PARM_size) {
1186
1187
1188
1189
1190
1191
1192#if ENABLE_LFS
1193#define XATOU_SFX xatoull_sfx
1194#else
1195#define XATOU_SFX xatoul_sfx
1196#endif
1197 static const struct suffix_mult find_suffixes[] = {
1198 { "c", 1 },
1199 { "w", 2 },
1200 { "", 512 },
1201 { "b", 512 },
1202 { "k", 1024 },
1203 { "", 0 }
1204 };
1205 action_size *ap;
1206 dbg("%d", __LINE__);
1207 ap = ALLOC_ACTION(size);
1208 ap->size_char = arg1[0];
1209 ap->size = XATOU_SFX(plus_minus_num(arg1), find_suffixes);
1210 }
1211#endif
1212#if ENABLE_FEATURE_FIND_CONTEXT
1213 else if (parm == PARM_context) {
1214 action_context *ap;
1215 dbg("%d", __LINE__);
1216 ap = ALLOC_ACTION(context);
1217
1218
1219 if (selinux_raw_to_trans_context((char*)arg1, &ap->context))
1220 bb_simple_perror_msg(arg1);
1221 }
1222#endif
1223#if ENABLE_FEATURE_FIND_LINKS
1224 else if (parm == PARM_links) {
1225 action_links *ap;
1226 dbg("%d", __LINE__);
1227 ap = ALLOC_ACTION(links);
1228 ap->links_char = arg1[0];
1229 ap->links_count = xatoul(plus_minus_num(arg1));
1230 }
1231#endif
1232 else {
1233 bb_error_msg("unrecognized: %s", arg);
1234 bb_show_usage();
1235 }
1236 argv++;
1237 }
1238 dbg("exiting %s", __func__);
1239 return appp;
1240#undef ALLOC_ACTION
1241}
1242
1243int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1244int find_main(int argc UNUSED_PARAM, char **argv)
1245{
1246 int i, firstopt, status = EXIT_SUCCESS;
1247
1248 INIT_G();
1249
1250 argv++;
1251 for (firstopt = 0; argv[firstopt]; firstopt++) {
1252 if (argv[firstopt][0] == '-')
1253 break;
1254 if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!'))
1255 break;
1256 if (ENABLE_FEATURE_FIND_PAREN && LONE_CHAR(argv[firstopt], '('))
1257 break;
1258 }
1259 if (firstopt == 0) {
1260 *--argv = (char*)".";
1261 firstopt++;
1262 }
1263
1264 G.actions = parse_params(&argv[firstopt]);
1265 argv[firstopt] = NULL;
1266
1267#if ENABLE_FEATURE_FIND_XDEV
1268 if (G.xdev_on) {
1269 struct stat stbuf;
1270
1271 G.xdev_count = firstopt;
1272 G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0]));
1273 for (i = 0; argv[i]; i++) {
1274
1275
1276 if (stat(argv[i], &stbuf) == 0)
1277 G.xdev_dev[i] = stbuf.st_dev;
1278
1279
1280
1281 }
1282 }
1283#endif
1284
1285 for (i = 0; argv[i]; i++) {
1286 if (!recursive_action(argv[i],
1287 G.recurse_flags,
1288 fileAction,
1289 fileAction,
1290 NULL,
1291 0)
1292 ) {
1293 status = EXIT_FAILURE;
1294 }
1295 }
1296
1297 return status;
1298}
1299