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 = xmalloc(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 ap->exec_argc = 0;
858 while (1) {
859 if (!*argv)
860 bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
861 if (LONE_CHAR(argv[0], ';'))
862 break;
863
864
865
866
867 argv++;
868 ap->exec_argc++;
869 }
870 if (ap->exec_argc == 0)
871 bb_error_msg_and_die(bb_msg_requires_arg, arg);
872 ap->subst_count = xmalloc(ap->exec_argc * sizeof(int));
873 i = ap->exec_argc;
874 while (i--)
875 ap->subst_count[i] = count_subst(ap->exec_argv[i]);
876 }
877#endif
878#if ENABLE_FEATURE_FIND_PAREN
879 else if (parm == PARM_char_brace) {
880 action_paren *ap;
881 char **endarg;
882 unsigned nested = 1;
883
884 endarg = argv;
885 while (1) {
886 if (!*++endarg)
887 bb_error_msg_and_die("unpaired '('");
888 if (LONE_CHAR(*endarg, '('))
889 nested++;
890 else if (LONE_CHAR(*endarg, ')') && !--nested) {
891 *endarg = NULL;
892 break;
893 }
894 }
895 ap = ALLOC_ACTION(paren);
896 ap->subexpr = parse_params(argv + 1);
897 *endarg = (char*) ")";
898 argv = endarg;
899 }
900#endif
901 else if (parm == PARM_name || parm == PARM_iname) {
902 action_name *ap;
903 ap = ALLOC_ACTION(name);
904 ap->pattern = arg1;
905 ap->iname = (parm == PARM_iname);
906 }
907#if ENABLE_FEATURE_FIND_PATH
908 else if (parm == PARM_path) {
909 action_path *ap;
910 ap = ALLOC_ACTION(path);
911 ap->pattern = arg1;
912 }
913#endif
914#if ENABLE_FEATURE_FIND_REGEX
915 else if (parm == PARM_regex) {
916 action_regex *ap;
917 ap = ALLOC_ACTION(regex);
918 xregcomp(&ap->compiled_pattern, arg1, 0 );
919 }
920#endif
921#if ENABLE_FEATURE_FIND_TYPE
922 else if (parm == PARM_type) {
923 action_type *ap;
924 ap = ALLOC_ACTION(type);
925 ap->type_mask = find_type(arg1);
926 }
927#endif
928#if ENABLE_FEATURE_FIND_PERM
929
930
931
932
933
934 else if (parm == PARM_perm) {
935 action_perm *ap;
936 ap = ALLOC_ACTION(perm);
937 ap->perm_char = arg1[0];
938 arg1 = plus_minus_num(arg1);
939 ap->perm_mask = 0;
940 if (!bb_parse_mode(arg1, &ap->perm_mask))
941 bb_error_msg_and_die("invalid mode '%s'", arg1);
942 }
943#endif
944#if ENABLE_FEATURE_FIND_MTIME
945 else if (parm == PARM_mtime) {
946 action_mtime *ap;
947 ap = ALLOC_ACTION(mtime);
948 ap->mtime_char = arg1[0];
949 ap->mtime_days = xatoul(plus_minus_num(arg1));
950 }
951#endif
952#if ENABLE_FEATURE_FIND_MMIN
953 else if (parm == PARM_mmin) {
954 action_mmin *ap;
955 ap = ALLOC_ACTION(mmin);
956 ap->mmin_char = arg1[0];
957 ap->mmin_mins = xatoul(plus_minus_num(arg1));
958 }
959#endif
960#if ENABLE_FEATURE_FIND_NEWER
961 else if (parm == PARM_newer) {
962 struct stat stat_newer;
963 action_newer *ap;
964 ap = ALLOC_ACTION(newer);
965 xstat(arg1, &stat_newer);
966 ap->newer_mtime = stat_newer.st_mtime;
967 }
968#endif
969#if ENABLE_FEATURE_FIND_INUM
970 else if (parm == PARM_inum) {
971 action_inum *ap;
972 ap = ALLOC_ACTION(inum);
973 ap->inode_num = xatoul(arg1);
974 }
975#endif
976#if ENABLE_FEATURE_FIND_USER
977 else if (parm == PARM_user) {
978 action_user *ap;
979 ap = ALLOC_ACTION(user);
980 ap->uid = bb_strtou(arg1, NULL, 10);
981 if (errno)
982 ap->uid = xuname2uid(arg1);
983 }
984#endif
985#if ENABLE_FEATURE_FIND_GROUP
986 else if (parm == PARM_group) {
987 action_group *ap;
988 ap = ALLOC_ACTION(group);
989 ap->gid = bb_strtou(arg1, NULL, 10);
990 if (errno)
991 ap->gid = xgroup2gid(arg1);
992 }
993#endif
994#if ENABLE_FEATURE_FIND_SIZE
995 else if (parm == PARM_size) {
996
997
998
999
1000
1001
1002#if ENABLE_LFS
1003#define XATOU_SFX xatoull_sfx
1004#else
1005#define XATOU_SFX xatoul_sfx
1006#endif
1007 static const struct suffix_mult find_suffixes[] = {
1008 { "c", 1 },
1009 { "w", 2 },
1010 { "", 512 },
1011 { "b", 512 },
1012 { "k", 1024 },
1013 { "", 0 }
1014 };
1015 action_size *ap;
1016 ap = ALLOC_ACTION(size);
1017 ap->size_char = arg1[0];
1018 ap->size = XATOU_SFX(plus_minus_num(arg1), find_suffixes);
1019 }
1020#endif
1021#if ENABLE_FEATURE_FIND_CONTEXT
1022 else if (parm == PARM_context) {
1023 action_context *ap;
1024 ap = ALLOC_ACTION(context);
1025 ap->context = NULL;
1026
1027 if (selinux_raw_to_trans_context((char*)arg1, &ap->context))
1028 bb_simple_perror_msg(arg1);
1029 }
1030#endif
1031#if ENABLE_FEATURE_FIND_LINKS
1032 else if (parm == PARM_links) {
1033 action_links *ap;
1034 ap = ALLOC_ACTION(links);
1035 ap->links_char = arg1[0];
1036 ap->links_count = xatoul(plus_minus_num(arg1));
1037 }
1038#endif
1039 else {
1040 bb_error_msg("unrecognized: %s", arg);
1041 bb_show_usage();
1042 }
1043 argv++;
1044 }
1045 return appp;
1046#undef ALLOC_ACTION
1047}
1048
1049
1050
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
1136int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1137int find_main(int argc UNUSED_PARAM, char **argv)
1138{
1139 static const char options[] ALIGN1 =
1140 "-follow\0"
1141IF_FEATURE_FIND_XDEV( "-xdev\0" )
1142IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0")
1143 ;
1144 enum {
1145 OPT_FOLLOW,
1146IF_FEATURE_FIND_XDEV( OPT_XDEV ,)
1147IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
1148 };
1149
1150 char *arg;
1151 char **argp;
1152 int i, firstopt, status = EXIT_SUCCESS;
1153#if ENABLE_FEATURE_FIND_MAXDEPTH
1154 int minmaxdepth[2] = { 0, INT_MAX };
1155#else
1156#define minmaxdepth NULL
1157#endif
1158
1159 INIT_G();
1160
1161 for (firstopt = 1; argv[firstopt]; firstopt++) {
1162 if (argv[firstopt][0] == '-')
1163 break;
1164 if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!'))
1165 break;
1166#if ENABLE_FEATURE_FIND_PAREN
1167 if (LONE_CHAR(argv[firstopt], '('))
1168 break;
1169#endif
1170 }
1171 if (firstopt == 1) {
1172 argv[0] = (char*)".";
1173 argv--;
1174 firstopt++;
1175 }
1176
1177
1178
1179
1180
1181
1182
1183
1184 argp = &argv[firstopt];
1185 while ((arg = argp[0])) {
1186 int opt = index_in_strings(options, arg);
1187 if (opt == OPT_FOLLOW) {
1188 G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
1189 argp[0] = (char*)"-a";
1190 }
1191#if ENABLE_FEATURE_FIND_XDEV
1192 if (opt == OPT_XDEV) {
1193 struct stat stbuf;
1194 if (!G.xdev_count) {
1195 G.xdev_count = firstopt - 1;
1196 G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0]));
1197 for (i = 1; i < firstopt; i++) {
1198
1199
1200 if (stat(argv[i], &stbuf) == 0)
1201 G.xdev_dev[i-1] = stbuf.st_dev;
1202
1203
1204 }
1205 }
1206 argp[0] = (char*)"-a";
1207 }
1208#endif
1209#if ENABLE_FEATURE_FIND_MAXDEPTH
1210 if (opt == OPT_MINDEPTH || opt == OPT_MINDEPTH + 1) {
1211 if (!argp[1])
1212 bb_show_usage();
1213 minmaxdepth[opt - OPT_MINDEPTH] = xatoi_u(argp[1]);
1214 argp[0] = (char*)"-a";
1215 argp[1] = (char*)"-a";
1216 argp++;
1217 }
1218#endif
1219 argp++;
1220 }
1221
1222 G.actions = parse_params(&argv[firstopt]);
1223
1224 for (i = 1; i < firstopt; i++) {
1225 if (!recursive_action(argv[i],
1226 G.recurse_flags,
1227 fileAction,
1228 fileAction,
1229#if ENABLE_FEATURE_FIND_MAXDEPTH
1230 minmaxdepth,
1231#else
1232 NULL,
1233#endif
1234 0))
1235 status = EXIT_FAILURE;
1236 }
1237 return status;
1238}
1239