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