diff options
author | Ron Yorston <rmy@pobox.com> | 2012-03-22 13:15:08 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2012-03-22 13:15:08 +0000 |
commit | c0d4367d6b581eb5989c02815880cf0fa2851ae8 (patch) | |
tree | 868c266e627e2d7f65ba5a4d5f98a1c421453181 /findutils | |
parent | f6bad5ef766b0447158e3de2f55c35f1f6cecb58 (diff) | |
parent | da4441c44f6efccb6f7b7588404d9c6bfb7b6af8 (diff) | |
download | busybox-w32-c0d4367d6b581eb5989c02815880cf0fa2851ae8.tar.gz busybox-w32-c0d4367d6b581eb5989c02815880cf0fa2851ae8.tar.bz2 busybox-w32-c0d4367d6b581eb5989c02815880cf0fa2851ae8.zip |
Merge commit 'da4441c44f6efccb6f7b7588404d9c6bfb7b6af8' into merge
Conflicts:
libbb/vfork_daemon_rexec.c
networking/wget.c
procps/ps.c
Diffstat (limited to 'findutils')
-rw-r--r-- | findutils/find.c | 419 |
1 files changed, 197 insertions, 222 deletions
diff --git a/findutils/find.c b/findutils/find.c index f85381b47..9ae84fa0d 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
@@ -53,10 +53,6 @@ | |||
53 | * diff -u /tmp/std_find /tmp/bb_find && echo Identical | 53 | * diff -u /tmp/std_find /tmp/bb_find && echo Identical |
54 | */ | 54 | */ |
55 | 55 | ||
56 | //applet:IF_FIND(APPLET_NOEXEC(find, find, BB_DIR_USR_BIN, BB_SUID_DROP, find)) | ||
57 | |||
58 | //kbuild:lib-$(CONFIG_FIND) += find.o | ||
59 | |||
60 | //config:config FIND | 56 | //config:config FIND |
61 | //config: bool "find" | 57 | //config: bool "find" |
62 | //config: default y | 58 | //config: default y |
@@ -112,11 +108,11 @@ | |||
112 | //config: This option allows find to restrict searches to a single filesystem. | 108 | //config: This option allows find to restrict searches to a single filesystem. |
113 | //config: | 109 | //config: |
114 | //config:config FEATURE_FIND_MAXDEPTH | 110 | //config:config FEATURE_FIND_MAXDEPTH |
115 | //config: bool "Enable -maxdepth N" | 111 | //config: bool "Enable -mindepth N and -maxdepth N" |
116 | //config: default y | 112 | //config: default y |
117 | //config: depends on FIND | 113 | //config: depends on FIND |
118 | //config: help | 114 | //config: help |
119 | //config: This option enables -maxdepth N option. | 115 | //config: This option enables -mindepth N and -maxdepth N option. |
120 | //config: | 116 | //config: |
121 | //config:config FEATURE_FIND_NEWER | 117 | //config:config FEATURE_FIND_NEWER |
122 | //config: bool "Enable -newer: compare file modification times" | 118 | //config: bool "Enable -newer: compare file modification times" |
@@ -124,7 +120,7 @@ | |||
124 | //config: depends on FIND | 120 | //config: depends on FIND |
125 | //config: help | 121 | //config: help |
126 | //config: Support the 'find -newer' option for finding any files which have | 122 | //config: Support the 'find -newer' option for finding any files which have |
127 | //config: a modified time that is more recent than the specified FILE. | 123 | //config: modification time that is more recent than the specified FILE. |
128 | //config: | 124 | //config: |
129 | //config:config FEATURE_FIND_INUM | 125 | //config:config FEATURE_FIND_INUM |
130 | //config: bool "Enable -inum: inode number matching" | 126 | //config: bool "Enable -inum: inode number matching" |
@@ -230,6 +226,106 @@ | |||
230 | //config: help | 226 | //config: help |
231 | //config: Support the 'find -links' option for matching number of links. | 227 | //config: Support the 'find -links' option for matching number of links. |
232 | 228 | ||
229 | //applet:IF_FIND(APPLET_NOEXEC(find, find, BB_DIR_USR_BIN, BB_SUID_DROP, find)) | ||
230 | |||
231 | //kbuild:lib-$(CONFIG_FIND) += find.o | ||
232 | |||
233 | //usage:#define find_trivial_usage | ||
234 | //usage: "[PATH]... [OPTIONS] [ACTIONS]" | ||
235 | //usage:#define find_full_usage "\n\n" | ||
236 | //usage: "Search for files and perform actions on them.\n" | ||
237 | //usage: "First failed action stops processing of current file.\n" | ||
238 | //usage: "Defaults: PATH is current directory, action is '-print'\n" | ||
239 | //usage: "\nOptions:" | ||
240 | //usage: "\n -follow Follow symlinks" | ||
241 | //usage: IF_FEATURE_FIND_XDEV( | ||
242 | //usage: "\n -xdev Don't descend directories on other filesystems" | ||
243 | //usage: ) | ||
244 | //usage: IF_FEATURE_FIND_MAXDEPTH( | ||
245 | //usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" | ||
246 | //usage: "\n actions to command line arguments only" | ||
247 | //usage: "\n -mindepth N Don't act on first N levels" | ||
248 | //usage: ) | ||
249 | //usage: IF_FEATURE_FIND_DEPTH( | ||
250 | //usage: "\n -depth Act on directory *after* traversing it" | ||
251 | //usage: ) | ||
252 | //usage: "\n" | ||
253 | //usage: "\nActions:" | ||
254 | //usage: IF_FEATURE_FIND_PAREN( | ||
255 | //usage: "\n ( ACTIONS ) Group actions for -o / -a" | ||
256 | //usage: ) | ||
257 | //usage: IF_FEATURE_FIND_NOT( | ||
258 | //usage: "\n ! ACT Invert ACT's success/failure" | ||
259 | //usage: ) | ||
260 | //usage: "\n ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2" | ||
261 | //usage: "\n ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2" | ||
262 | //usage: "\n Note: -a has higher priority than -o" | ||
263 | //usage: "\n -name PATTERN Match file name (w/o directory name) to PATTERN" | ||
264 | //usage: "\n -iname PATTERN Case insensitive -name" | ||
265 | //usage: IF_FEATURE_FIND_PATH( | ||
266 | //usage: "\n -path PATTERN Match path to PATTERN" | ||
267 | //usage: ) | ||
268 | //usage: IF_FEATURE_FIND_REGEX( | ||
269 | //usage: "\n -regex PATTERN Match path to regex PATTERN" | ||
270 | //usage: ) | ||
271 | //usage: IF_FEATURE_FIND_TYPE( | ||
272 | //usage: "\n -type X File type is X (one of: f,d,l,b,c,...)" | ||
273 | //usage: ) | ||
274 | //usage: IF_FEATURE_FIND_PERM( | ||
275 | //usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK)," | ||
276 | //usage: "\n or exactly MASK bits are set in file's mode" | ||
277 | //usage: ) | ||
278 | //usage: IF_FEATURE_FIND_MTIME( | ||
279 | //usage: "\n -mtime DAYS mtime is greater than (+N), less than (-N)," | ||
280 | //usage: "\n or exactly N days in the past" | ||
281 | //usage: ) | ||
282 | //usage: IF_FEATURE_FIND_MMIN( | ||
283 | //usage: "\n -mmin MINS mtime is greater than (+N), less than (-N)," | ||
284 | //usage: "\n or exactly N minutes in the past" | ||
285 | //usage: ) | ||
286 | //usage: IF_FEATURE_FIND_NEWER( | ||
287 | //usage: "\n -newer FILE mtime is more recent than FILE's" | ||
288 | //usage: ) | ||
289 | //usage: IF_FEATURE_FIND_INUM( | ||
290 | //usage: "\n -inum N File has inode number N" | ||
291 | //usage: ) | ||
292 | //usage: IF_FEATURE_FIND_USER( | ||
293 | //usage: "\n -user NAME/ID File is owned by given user" | ||
294 | //usage: ) | ||
295 | //usage: IF_FEATURE_FIND_GROUP( | ||
296 | //usage: "\n -group NAME/ID File is owned by given group" | ||
297 | //usage: ) | ||
298 | //usage: IF_FEATURE_FIND_SIZE( | ||
299 | //usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" | ||
300 | //usage: "\n +/-N: file size is bigger/smaller than N" | ||
301 | //usage: ) | ||
302 | //usage: IF_FEATURE_FIND_LINKS( | ||
303 | //usage: "\n -links N Number of links is greater than (+N), less than (-N)," | ||
304 | //usage: "\n or exactly N" | ||
305 | //usage: ) | ||
306 | //usage: IF_FEATURE_FIND_CONTEXT( | ||
307 | //usage: "\n -context CTX File has specified security context" | ||
308 | //usage: ) | ||
309 | //usage: IF_FEATURE_FIND_PRUNE( | ||
310 | //usage: "\n -prune If current file is directory, don't descend into it" | ||
311 | //usage: ) | ||
312 | //usage: "\nIf none of the following actions is specified, -print is assumed" | ||
313 | //usage: "\n -print Print file name" | ||
314 | //usage: IF_FEATURE_FIND_PRINT0( | ||
315 | //usage: "\n -print0 Print file name, NUL terminated" | ||
316 | //usage: ) | ||
317 | //usage: IF_FEATURE_FIND_EXEC( | ||
318 | //usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by" | ||
319 | //usage: "\n file name. Fails if CMD exits with nonzero" | ||
320 | //usage: ) | ||
321 | //usage: IF_FEATURE_FIND_DELETE( | ||
322 | //usage: "\n -delete Delete current file/directory. Turns on -depth option" | ||
323 | //usage: ) | ||
324 | //usage: | ||
325 | //usage:#define find_example_usage | ||
326 | //usage: "$ find / -name passwd\n" | ||
327 | //usage: "/etc/passwd\n" | ||
328 | |||
233 | #include <fnmatch.h> | 329 | #include <fnmatch.h> |
234 | #include "libbb.h" | 330 | #include "libbb.h" |
235 | #if ENABLE_FEATURE_FIND_REGEX | 331 | #if ENABLE_FEATURE_FIND_REGEX |
@@ -278,8 +374,12 @@ IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;)) | |||
278 | struct globals { | 374 | struct globals { |
279 | IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;) | 375 | IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;) |
280 | IF_FEATURE_FIND_XDEV(int xdev_count;) | 376 | IF_FEATURE_FIND_XDEV(int xdev_count;) |
377 | #if ENABLE_FEATURE_FIND_MAXDEPTH | ||
378 | int minmaxdepth[2]; | ||
379 | #endif | ||
281 | action ***actions; | 380 | action ***actions; |
282 | bool need_print; | 381 | smallint need_print; |
382 | smallint xdev_on; | ||
283 | recurse_flags_t recurse_flags; | 383 | recurse_flags_t recurse_flags; |
284 | } FIX_ALIASING; | 384 | } FIX_ALIASING; |
285 | #define G (*(struct globals*)&bb_common_bufsiz1) | 385 | #define G (*(struct globals*)&bb_common_bufsiz1) |
@@ -288,7 +388,8 @@ struct globals { | |||
288 | char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ | 388 | char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ |
289 | }; \ | 389 | }; \ |
290 | /* we have to zero it out because of NOEXEC */ \ | 390 | /* we have to zero it out because of NOEXEC */ \ |
291 | memset(&G, 0, offsetof(struct globals, need_print)); \ | 391 | memset(&G, 0, sizeof(G)); \ |
392 | IF_FEATURE_FIND_MAXDEPTH(G.minmaxdepth[1] = INT_MAX;) \ | ||
292 | G.need_print = 1; \ | 393 | G.need_print = 1; \ |
293 | G.recurse_flags = ACTION_RECURSE; \ | 394 | G.recurse_flags = ACTION_RECURSE; \ |
294 | } while (0) | 395 | } while (0) |
@@ -586,16 +687,15 @@ ACTF(links) | |||
586 | 687 | ||
587 | static int FAST_FUNC fileAction(const char *fileName, | 688 | static int FAST_FUNC fileAction(const char *fileName, |
588 | struct stat *statbuf, | 689 | struct stat *statbuf, |
589 | void *userData IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM), | 690 | void *userData UNUSED_PARAM, |
590 | int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM)) | 691 | int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM)) |
591 | { | 692 | { |
592 | int r; | 693 | int r; |
593 | #if ENABLE_FEATURE_FIND_MAXDEPTH | ||
594 | #define minmaxdepth ((int*)userData) | ||
595 | 694 | ||
596 | if (depth < minmaxdepth[0]) | 695 | #if ENABLE_FEATURE_FIND_MAXDEPTH |
696 | if (depth < G.minmaxdepth[0]) | ||
597 | return TRUE; /* skip this, continue recursing */ | 697 | return TRUE; /* skip this, continue recursing */ |
598 | if (depth > minmaxdepth[1]) | 698 | if (depth > G.minmaxdepth[1]) |
599 | return SKIP; /* stop recursing */ | 699 | return SKIP; /* stop recursing */ |
600 | #endif | 700 | #endif |
601 | 701 | ||
@@ -606,7 +706,7 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
606 | 706 | ||
607 | #if ENABLE_FEATURE_FIND_MAXDEPTH | 707 | #if ENABLE_FEATURE_FIND_MAXDEPTH |
608 | if (S_ISDIR(statbuf->st_mode)) { | 708 | if (S_ISDIR(statbuf->st_mode)) { |
609 | if (depth == minmaxdepth[1]) | 709 | if (depth == G.minmaxdepth[1]) |
610 | return SKIP; | 710 | return SKIP; |
611 | } | 711 | } |
612 | #endif | 712 | #endif |
@@ -629,7 +729,6 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
629 | /* Cannot return 0: our caller, recursive_action(), | 729 | /* Cannot return 0: our caller, recursive_action(), |
630 | * will perror() and skip dirs (if called on dir) */ | 730 | * will perror() and skip dirs (if called on dir) */ |
631 | return (r & SKIP) ? SKIP : TRUE; | 731 | return (r & SKIP) ? SKIP : TRUE; |
632 | #undef minmaxdepth | ||
633 | } | 732 | } |
634 | 733 | ||
635 | 734 | ||
@@ -674,6 +773,9 @@ static const char* plus_minus_num(const char* str) | |||
674 | static action*** parse_params(char **argv) | 773 | static action*** parse_params(char **argv) |
675 | { | 774 | { |
676 | enum { | 775 | enum { |
776 | OPT_FOLLOW , | ||
777 | IF_FEATURE_FIND_XDEV( OPT_XDEV ,) | ||
778 | IF_FEATURE_FIND_DEPTH( OPT_DEPTH ,) | ||
677 | PARM_a , | 779 | PARM_a , |
678 | PARM_o , | 780 | PARM_o , |
679 | IF_FEATURE_FIND_NOT( PARM_char_not ,) | 781 | IF_FEATURE_FIND_NOT( PARM_char_not ,) |
@@ -684,12 +786,11 @@ static action*** parse_params(char **argv) | |||
684 | #endif | 786 | #endif |
685 | PARM_print , | 787 | PARM_print , |
686 | IF_FEATURE_FIND_PRINT0( PARM_print0 ,) | 788 | IF_FEATURE_FIND_PRINT0( PARM_print0 ,) |
687 | IF_FEATURE_FIND_DEPTH( PARM_depth ,) | ||
688 | IF_FEATURE_FIND_PRUNE( PARM_prune ,) | 789 | IF_FEATURE_FIND_PRUNE( PARM_prune ,) |
689 | IF_FEATURE_FIND_DELETE( PARM_delete ,) | 790 | IF_FEATURE_FIND_DELETE( PARM_delete ,) |
690 | IF_FEATURE_FIND_EXEC( PARM_exec ,) | 791 | IF_FEATURE_FIND_EXEC( PARM_exec ,) |
691 | IF_FEATURE_FIND_PAREN( PARM_char_brace,) | 792 | IF_FEATURE_FIND_PAREN( PARM_char_brace,) |
692 | /* All options starting from here require argument */ | 793 | /* All options/actions starting from here require argument */ |
693 | PARM_name , | 794 | PARM_name , |
694 | PARM_iname , | 795 | PARM_iname , |
695 | IF_FEATURE_FIND_PATH( PARM_path ,) | 796 | IF_FEATURE_FIND_PATH( PARM_path ,) |
@@ -705,25 +806,28 @@ static action*** parse_params(char **argv) | |||
705 | IF_FEATURE_FIND_SIZE( PARM_size ,) | 806 | IF_FEATURE_FIND_SIZE( PARM_size ,) |
706 | IF_FEATURE_FIND_CONTEXT(PARM_context ,) | 807 | IF_FEATURE_FIND_CONTEXT(PARM_context ,) |
707 | IF_FEATURE_FIND_LINKS( PARM_links ,) | 808 | IF_FEATURE_FIND_LINKS( PARM_links ,) |
809 | IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,OPT_MAXDEPTH,) | ||
708 | }; | 810 | }; |
709 | 811 | ||
710 | static const char params[] ALIGN1 = | 812 | static const char params[] ALIGN1 = |
711 | "-a\0" | 813 | "-follow\0" |
712 | "-o\0" | 814 | IF_FEATURE_FIND_XDEV( "-xdev\0" ) |
815 | IF_FEATURE_FIND_DEPTH( "-depth\0" ) | ||
816 | "-a\0" | ||
817 | "-o\0" | ||
713 | IF_FEATURE_FIND_NOT( "!\0" ) | 818 | IF_FEATURE_FIND_NOT( "!\0" ) |
714 | #if ENABLE_DESKTOP | 819 | #if ENABLE_DESKTOP |
715 | "-and\0" | 820 | "-and\0" |
716 | "-or\0" | 821 | "-or\0" |
717 | IF_FEATURE_FIND_NOT( "-not\0" ) | 822 | IF_FEATURE_FIND_NOT( "-not\0" ) |
718 | #endif | 823 | #endif |
719 | "-print\0" | 824 | "-print\0" |
720 | IF_FEATURE_FIND_PRINT0( "-print0\0" ) | 825 | IF_FEATURE_FIND_PRINT0( "-print0\0" ) |
721 | IF_FEATURE_FIND_DEPTH( "-depth\0" ) | ||
722 | IF_FEATURE_FIND_PRUNE( "-prune\0" ) | 826 | IF_FEATURE_FIND_PRUNE( "-prune\0" ) |
723 | IF_FEATURE_FIND_DELETE( "-delete\0" ) | 827 | IF_FEATURE_FIND_DELETE( "-delete\0" ) |
724 | IF_FEATURE_FIND_EXEC( "-exec\0" ) | 828 | IF_FEATURE_FIND_EXEC( "-exec\0" ) |
725 | IF_FEATURE_FIND_PAREN( "(\0" ) | 829 | IF_FEATURE_FIND_PAREN( "(\0" ) |
726 | /* All options starting from here require argument */ | 830 | /* All options/actions starting from here require argument */ |
727 | "-name\0" | 831 | "-name\0" |
728 | "-iname\0" | 832 | "-iname\0" |
729 | IF_FEATURE_FIND_PATH( "-path\0" ) | 833 | IF_FEATURE_FIND_PATH( "-path\0" ) |
@@ -739,7 +843,8 @@ static action*** parse_params(char **argv) | |||
739 | IF_FEATURE_FIND_SIZE( "-size\0" ) | 843 | IF_FEATURE_FIND_SIZE( "-size\0" ) |
740 | IF_FEATURE_FIND_CONTEXT("-context\0") | 844 | IF_FEATURE_FIND_CONTEXT("-context\0") |
741 | IF_FEATURE_FIND_LINKS( "-links\0" ) | 845 | IF_FEATURE_FIND_LINKS( "-links\0" ) |
742 | ; | 846 | IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") |
847 | ; | ||
743 | 848 | ||
744 | action*** appp; | 849 | action*** appp; |
745 | unsigned cur_group = 0; | 850 | unsigned cur_group = 0; |
@@ -766,27 +871,13 @@ static action*** parse_params(char **argv) | |||
766 | 871 | ||
767 | appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */ | 872 | appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */ |
768 | 873 | ||
769 | /* Actions have side effects and return a true or false value | ||
770 | * We implement: -print, -print0, -exec | ||
771 | * | ||
772 | * The rest are tests. | ||
773 | * | ||
774 | * Tests and actions are grouped by operators | ||
775 | * ( expr ) Force precedence | ||
776 | * ! expr True if expr is false | ||
777 | * -not expr Same as ! expr | ||
778 | * expr1 [-a[nd]] expr2 And; expr2 is not evaluated if expr1 is false | ||
779 | * expr1 -o[r] expr2 Or; expr2 is not evaluated if expr1 is true | ||
780 | * expr1 , expr2 List; both expr1 and expr2 are always evaluated | ||
781 | * We implement: (), -a, -o | ||
782 | */ | ||
783 | while (*argv) { | 874 | while (*argv) { |
784 | const char *arg = argv[0]; | 875 | const char *arg = argv[0]; |
785 | int parm = index_in_strings(params, arg); | 876 | int parm = index_in_strings(params, arg); |
786 | const char *arg1 = argv[1]; | 877 | const char *arg1 = argv[1]; |
787 | 878 | ||
788 | if (parm >= PARM_name) { | 879 | if (parm >= PARM_name) { |
789 | /* All options starting from -name require argument */ | 880 | /* All options/actions starting from -name require argument */ |
790 | if (!arg1) | 881 | if (!arg1) |
791 | bb_error_msg_and_die(bb_msg_requires_arg, arg); | 882 | bb_error_msg_and_die(bb_msg_requires_arg, arg); |
792 | argv++; | 883 | argv++; |
@@ -795,8 +886,37 @@ static action*** parse_params(char **argv) | |||
795 | /* We can use big switch() here, but on i386 | 886 | /* We can use big switch() here, but on i386 |
796 | * it doesn't give smaller code. Other arches? */ | 887 | * it doesn't give smaller code. Other arches? */ |
797 | 888 | ||
798 | /* --- Operators --- */ | 889 | /* Options always return true. They always take effect |
799 | if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) { | 890 | * rather than being processed only when their place in the |
891 | * expression is reached. | ||
892 | */ | ||
893 | /* Options */ | ||
894 | #if ENABLE_FEATURE_FIND_XDEV | ||
895 | if (parm == OPT_XDEV) { | ||
896 | G.xdev_on = 1; | ||
897 | } | ||
898 | #endif | ||
899 | #if ENABLE_FEATURE_FIND_MAXDEPTH | ||
900 | else if (parm == OPT_MINDEPTH || parm == OPT_MINDEPTH + 1) { | ||
901 | G.minmaxdepth[parm - OPT_MINDEPTH] = xatoi_positive(arg1); | ||
902 | } | ||
903 | #endif | ||
904 | #if ENABLE_FEATURE_FIND_DEPTH | ||
905 | else if (parm == OPT_DEPTH) { | ||
906 | G.recurse_flags |= ACTION_DEPTHFIRST; | ||
907 | } | ||
908 | #endif | ||
909 | /* Actions are grouped by operators | ||
910 | * ( expr ) Force precedence | ||
911 | * ! expr True if expr is false | ||
912 | * -not expr Same as ! expr | ||
913 | * expr1 [-a[nd]] expr2 And; expr2 is not evaluated if expr1 is false | ||
914 | * expr1 -o[r] expr2 Or; expr2 is not evaluated if expr1 is true | ||
915 | * expr1 , expr2 List; both expr1 and expr2 are always evaluated | ||
916 | * We implement: (), -a, -o | ||
917 | */ | ||
918 | /* Operators */ | ||
919 | else if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) { | ||
800 | /* no further special handling required */ | 920 | /* no further special handling required */ |
801 | } | 921 | } |
802 | else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) { | 922 | else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) { |
@@ -813,29 +933,19 @@ static action*** parse_params(char **argv) | |||
813 | invert_flag ^= 1; | 933 | invert_flag ^= 1; |
814 | } | 934 | } |
815 | #endif | 935 | #endif |
816 | 936 | /* Actions */ | |
817 | /* --- Tests and actions --- */ | ||
818 | else if (parm == PARM_print) { | 937 | else if (parm == PARM_print) { |
819 | G.need_print = 0; | 938 | G.need_print = 0; |
820 | /* GNU find ignores '!' here: "find ! -print" */ | ||
821 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | ||
822 | (void) ALLOC_ACTION(print); | 939 | (void) ALLOC_ACTION(print); |
823 | } | 940 | } |
824 | #if ENABLE_FEATURE_FIND_PRINT0 | 941 | #if ENABLE_FEATURE_FIND_PRINT0 |
825 | else if (parm == PARM_print0) { | 942 | else if (parm == PARM_print0) { |
826 | G.need_print = 0; | 943 | G.need_print = 0; |
827 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | ||
828 | (void) ALLOC_ACTION(print0); | 944 | (void) ALLOC_ACTION(print0); |
829 | } | 945 | } |
830 | #endif | 946 | #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 | 947 | #if ENABLE_FEATURE_FIND_PRUNE |
837 | else if (parm == PARM_prune) { | 948 | else if (parm == PARM_prune) { |
838 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | ||
839 | (void) ALLOC_ACTION(prune); | 949 | (void) ALLOC_ACTION(prune); |
840 | } | 950 | } |
841 | #endif | 951 | #endif |
@@ -851,7 +961,6 @@ static action*** parse_params(char **argv) | |||
851 | int i; | 961 | int i; |
852 | action_exec *ap; | 962 | action_exec *ap; |
853 | G.need_print = 0; | 963 | G.need_print = 0; |
854 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | ||
855 | ap = ALLOC_ACTION(exec); | 964 | ap = ALLOC_ACTION(exec); |
856 | ap->exec_argv = ++argv; /* first arg after -exec */ | 965 | ap->exec_argv = ++argv; /* first arg after -exec */ |
857 | /*ap->exec_argc = 0; - ALLOC_ACTION did it */ | 966 | /*ap->exec_argc = 0; - ALLOC_ACTION did it */ |
@@ -859,9 +968,9 @@ static action*** parse_params(char **argv) | |||
859 | if (!*argv) /* did not see ';' or '+' until end */ | 968 | if (!*argv) /* did not see ';' or '+' until end */ |
860 | bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); | 969 | bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); |
861 | // find -exec echo Foo ">{}<" ";" | 970 | // find -exec echo Foo ">{}<" ";" |
862 | // executes "echo Foo <filename>", | 971 | // executes "echo Foo >FILENAME<", |
863 | // find -exec echo Foo ">{}<" "+" | 972 | // find -exec echo Foo ">{}<" "+" |
864 | // executes "echo Foo <filename1> <filename2> <filename3>...". | 973 | // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...". |
865 | // TODO (so far we treat "+" just like ";") | 974 | // TODO (so far we treat "+" just like ";") |
866 | if ((argv[0][0] == ';' || argv[0][0] == '+') | 975 | if ((argv[0][0] == ';' || argv[0][0] == '+') |
867 | && argv[0][1] == '\0' | 976 | && argv[0][1] == '\0' |
@@ -930,10 +1039,10 @@ static action*** parse_params(char **argv) | |||
930 | } | 1039 | } |
931 | #endif | 1040 | #endif |
932 | #if ENABLE_FEATURE_FIND_PERM | 1041 | #if ENABLE_FEATURE_FIND_PERM |
933 | /* -perm mode File's permission bits are exactly mode (octal or symbolic). | 1042 | /* -perm BITS File's mode bits are exactly BITS (octal or symbolic). |
934 | * Symbolic modes use mode 0 as a point of departure. | 1043 | * Symbolic modes use mode 0 as a point of departure. |
935 | * -perm -mode All of the permission bits mode are set for the file. | 1044 | * -perm -BITS All of the BITS are set in file's mode. |
936 | * -perm +mode Any of the permission bits mode are set for the file. | 1045 | * -perm +BITS At least one of the BITS is set in file's mode. |
937 | */ | 1046 | */ |
938 | else if (parm == PARM_perm) { | 1047 | else if (parm == PARM_perm) { |
939 | action_perm *ap; | 1048 | action_perm *ap; |
@@ -1050,193 +1159,59 @@ static action*** parse_params(char **argv) | |||
1050 | #undef ALLOC_ACTION | 1159 | #undef ALLOC_ACTION |
1051 | } | 1160 | } |
1052 | 1161 | ||
1053 | //usage:#define find_trivial_usage | ||
1054 | //usage: "[PATH]... [EXPRESSION]" | ||
1055 | //usage:#define find_full_usage "\n\n" | ||
1056 | //usage: "Search for files. The default PATH is the current directory,\n" | ||
1057 | //usage: "default EXPRESSION is '-print'\n" | ||
1058 | //usage: "\nEXPRESSION may consist of:" | ||
1059 | //usage: "\n -follow Follow symlinks" | ||
1060 | //usage: IF_FEATURE_FIND_XDEV( | ||
1061 | //usage: "\n -xdev Don't descend directories on other filesystems" | ||
1062 | //usage: ) | ||
1063 | //usage: IF_FEATURE_FIND_MAXDEPTH( | ||
1064 | //usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" | ||
1065 | //usage: "\n tests/actions to command line arguments only" | ||
1066 | //usage: ) | ||
1067 | //usage: "\n -mindepth N Don't act on first N levels" | ||
1068 | //usage: "\n -name PATTERN File name (w/o directory name) matches PATTERN" | ||
1069 | //usage: "\n -iname PATTERN Case insensitive -name" | ||
1070 | //usage: IF_FEATURE_FIND_PATH( | ||
1071 | //usage: "\n -path PATTERN Path matches PATTERN" | ||
1072 | //usage: ) | ||
1073 | //usage: IF_FEATURE_FIND_REGEX( | ||
1074 | //usage: "\n -regex PATTERN Path matches regex PATTERN" | ||
1075 | //usage: ) | ||
1076 | //usage: IF_FEATURE_FIND_TYPE( | ||
1077 | //usage: "\n -type X File type is X (X is one of: f,d,l,b,c,...)" | ||
1078 | //usage: ) | ||
1079 | //usage: IF_FEATURE_FIND_PERM( | ||
1080 | //usage: "\n -perm NNN Permissions match any of (+NNN), all of (-NNN)," | ||
1081 | //usage: "\n or exactly NNN" | ||
1082 | //usage: ) | ||
1083 | //usage: IF_FEATURE_FIND_MTIME( | ||
1084 | //usage: "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," | ||
1085 | //usage: "\n or exactly N days" | ||
1086 | //usage: ) | ||
1087 | //usage: IF_FEATURE_FIND_MMIN( | ||
1088 | //usage: "\n -mmin MINS Modified time is greater than (+N), less than (-N)," | ||
1089 | //usage: "\n or exactly N minutes" | ||
1090 | //usage: ) | ||
1091 | //usage: IF_FEATURE_FIND_NEWER( | ||
1092 | //usage: "\n -newer FILE Modified time is more recent than FILE's" | ||
1093 | //usage: ) | ||
1094 | //usage: IF_FEATURE_FIND_INUM( | ||
1095 | //usage: "\n -inum N File has inode number N" | ||
1096 | //usage: ) | ||
1097 | //usage: IF_FEATURE_FIND_USER( | ||
1098 | //usage: "\n -user NAME File is owned by user NAME (numeric user ID allowed)" | ||
1099 | //usage: ) | ||
1100 | //usage: IF_FEATURE_FIND_GROUP( | ||
1101 | //usage: "\n -group NAME File belongs to group NAME (numeric group ID allowed)" | ||
1102 | //usage: ) | ||
1103 | //usage: IF_FEATURE_FIND_DEPTH( | ||
1104 | //usage: "\n -depth Process directory name after traversing it" | ||
1105 | //usage: ) | ||
1106 | //usage: IF_FEATURE_FIND_SIZE( | ||
1107 | //usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" | ||
1108 | //usage: "\n +/-N: file size is bigger/smaller than N" | ||
1109 | //usage: ) | ||
1110 | //usage: IF_FEATURE_FIND_LINKS( | ||
1111 | //usage: "\n -links N Number of links is greater than (+N), less than (-N)," | ||
1112 | //usage: "\n or exactly N" | ||
1113 | //usage: ) | ||
1114 | //usage: "\n -print Print (default and assumed)" | ||
1115 | //usage: IF_FEATURE_FIND_PRINT0( | ||
1116 | //usage: "\n -print0 Delimit output with null characters rather than" | ||
1117 | //usage: "\n newlines" | ||
1118 | //usage: ) | ||
1119 | //usage: IF_FEATURE_FIND_CONTEXT( | ||
1120 | //usage: "\n -context File has specified security context" | ||
1121 | //usage: ) | ||
1122 | //usage: IF_FEATURE_FIND_EXEC( | ||
1123 | //usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by the" | ||
1124 | //usage: "\n matching files" | ||
1125 | //usage: ) | ||
1126 | //usage: IF_FEATURE_FIND_PRUNE( | ||
1127 | //usage: "\n -prune Stop traversing current subtree" | ||
1128 | //usage: ) | ||
1129 | //usage: IF_FEATURE_FIND_DELETE( | ||
1130 | //usage: "\n -delete Delete files, turns on -depth option" | ||
1131 | //usage: ) | ||
1132 | //usage: IF_FEATURE_FIND_PAREN( | ||
1133 | //usage: "\n (EXPR) Group an expression" | ||
1134 | //usage: ) | ||
1135 | //usage: | ||
1136 | //usage:#define find_example_usage | ||
1137 | //usage: "$ find / -name passwd\n" | ||
1138 | //usage: "/etc/passwd\n" | ||
1139 | |||
1140 | int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1162 | int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1141 | int find_main(int argc UNUSED_PARAM, char **argv) | 1163 | int find_main(int argc UNUSED_PARAM, char **argv) |
1142 | { | 1164 | { |
1143 | static const char options[] ALIGN1 = | ||
1144 | "-follow\0" | ||
1145 | IF_FEATURE_FIND_XDEV( "-xdev\0" ) | ||
1146 | IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") | ||
1147 | ; | ||
1148 | enum { | ||
1149 | OPT_FOLLOW, | ||
1150 | IF_FEATURE_FIND_XDEV( OPT_XDEV ,) | ||
1151 | IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | ||
1152 | }; | ||
1153 | |||
1154 | char *arg; | ||
1155 | char **argp; | ||
1156 | int i, firstopt, status = EXIT_SUCCESS; | 1165 | 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 | 1166 | ||
1163 | INIT_G(); | 1167 | INIT_G(); |
1164 | 1168 | ||
1165 | for (firstopt = 1; argv[firstopt]; firstopt++) { | 1169 | argv++; |
1170 | for (firstopt = 0; argv[firstopt]; firstopt++) { | ||
1166 | if (argv[firstopt][0] == '-') | 1171 | if (argv[firstopt][0] == '-') |
1167 | break; | 1172 | break; |
1168 | if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!')) | 1173 | if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!')) |
1169 | break; | 1174 | break; |
1170 | #if ENABLE_FEATURE_FIND_PAREN | 1175 | if (ENABLE_FEATURE_FIND_PAREN && LONE_CHAR(argv[firstopt], '(')) |
1171 | if (LONE_CHAR(argv[firstopt], '(')) | ||
1172 | break; | 1176 | break; |
1173 | #endif | ||
1174 | } | 1177 | } |
1175 | if (firstopt == 1) { | 1178 | if (firstopt == 0) { |
1176 | argv[0] = (char*)"."; | 1179 | *--argv = (char*)"."; |
1177 | argv--; | ||
1178 | firstopt++; | 1180 | firstopt++; |
1179 | } | 1181 | } |
1180 | 1182 | ||
1181 | /* All options always return true. They always take effect | 1183 | G.actions = parse_params(&argv[firstopt]); |
1182 | * rather than being processed only when their place in the | 1184 | argv[firstopt] = NULL; |
1183 | * expression is reached. | 1185 | |
1184 | * We implement: -follow, -xdev, -maxdepth | ||
1185 | */ | ||
1186 | /* Process options, and replace then with -a */ | ||
1187 | /* (-a will be ignored by recursive parser later) */ | ||
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 | 1186 | #if ENABLE_FEATURE_FIND_XDEV |
1196 | if (opt == OPT_XDEV) { | 1187 | if (G.xdev_on) { |
1197 | struct stat stbuf; | 1188 | struct stat stbuf; |
1198 | if (!G.xdev_count) { | 1189 | |
1199 | G.xdev_count = firstopt - 1; | 1190 | G.xdev_count = firstopt; |
1200 | G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0])); | 1191 | G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0])); |
1201 | for (i = 1; i < firstopt; i++) { | 1192 | for (i = 0; argv[i]; i++) { |
1202 | /* not xstat(): shouldn't bomb out on | 1193 | /* not xstat(): shouldn't bomb out on |
1203 | * "find not_exist exist -xdev" */ | 1194 | * "find not_exist exist -xdev" */ |
1204 | if (stat(argv[i], &stbuf) == 0) | 1195 | if (stat(argv[i], &stbuf) == 0) |
1205 | G.xdev_dev[i-1] = stbuf.st_dev; | 1196 | G.xdev_dev[i] = stbuf.st_dev; |
1206 | /* else G.xdev_dev[i-1] stays 0 and | 1197 | /* else G.xdev_dev[i] stays 0 and |
1207 | * won't match any real device dev_t */ | 1198 | * won't match any real device dev_t |
1208 | } | 1199 | */ |
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 | } | 1200 | } |
1222 | #endif | ||
1223 | argp++; | ||
1224 | } | 1201 | } |
1202 | #endif | ||
1225 | 1203 | ||
1226 | G.actions = parse_params(&argv[firstopt]); | 1204 | for (i = 0; argv[i]; i++) { |
1227 | |||
1228 | for (i = 1; i < firstopt; i++) { | ||
1229 | if (!recursive_action(argv[i], | 1205 | if (!recursive_action(argv[i], |
1230 | G.recurse_flags,/* flags */ | 1206 | G.recurse_flags,/* flags */ |
1231 | fileAction, /* file action */ | 1207 | fileAction, /* file action */ |
1232 | fileAction, /* dir action */ | 1208 | fileAction, /* dir action */ |
1233 | #if ENABLE_FEATURE_FIND_MAXDEPTH | ||
1234 | minmaxdepth, /* user data */ | ||
1235 | #else | ||
1236 | NULL, /* user data */ | 1209 | NULL, /* user data */ |
1237 | #endif | 1210 | 0) /* depth */ |
1238 | 0)) /* depth */ | 1211 | ) { |
1239 | status = EXIT_FAILURE; | 1212 | status = EXIT_FAILURE; |
1213 | } | ||
1240 | } | 1214 | } |
1215 | |||
1241 | return status; | 1216 | return status; |
1242 | } | 1217 | } |