diff options
-rw-r--r-- | findutils/find.c | 79 | ||||
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/recursive_action.c | 19 |
3 files changed, 61 insertions, 39 deletions
diff --git a/findutils/find.c b/findutils/find.c index bd92e2281..6f7be4fc2 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
@@ -62,9 +62,6 @@ | |||
62 | /* This is a NOEXEC applet. Be very careful! */ | 62 | /* This is a NOEXEC applet. Be very careful! */ |
63 | 63 | ||
64 | 64 | ||
65 | IF_FEATURE_FIND_XDEV(static dev_t *xdev_dev;) | ||
66 | IF_FEATURE_FIND_XDEV(static int xdev_count;) | ||
67 | |||
68 | typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC; | 65 | typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC; |
69 | 66 | ||
70 | typedef struct { | 67 | typedef struct { |
@@ -100,9 +97,21 @@ IF_FEATURE_FIND_DELETE( ACTS(delete)) | |||
100 | IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) | 97 | IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) |
101 | IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) | 98 | IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) |
102 | 99 | ||
103 | static action ***actions; | 100 | struct globals { |
104 | static bool need_print = 1; | 101 | IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;) |
105 | static int recurse_flags = ACTION_RECURSE; | 102 | IF_FEATURE_FIND_XDEV(int xdev_count;) |
103 | action ***actions; | ||
104 | bool need_print; | ||
105 | recurse_flags_t recurse_flags; | ||
106 | }; | ||
107 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
108 | #define INIT_G() do { \ | ||
109 | struct G_sizecheck { \ | ||
110 | char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ | ||
111 | }; \ | ||
112 | G.need_print = 1; \ | ||
113 | G.recurse_flags = ACTION_RECURSE; \ | ||
114 | } while (0) | ||
106 | 115 | ||
107 | #if ENABLE_FEATURE_FIND_EXEC | 116 | #if ENABLE_FEATURE_FIND_EXEC |
108 | static unsigned count_subst(const char *str) | 117 | static unsigned count_subst(const char *str) |
@@ -367,7 +376,7 @@ ACTF(context) | |||
367 | security_context_t con; | 376 | security_context_t con; |
368 | int rc; | 377 | int rc; |
369 | 378 | ||
370 | if (recurse_flags & ACTION_FOLLOWLINKS) { | 379 | if (G.recurse_flags & ACTION_FOLLOWLINKS) { |
371 | rc = getfilecon(fileName, &con); | 380 | rc = getfilecon(fileName, &con); |
372 | } else { | 381 | } else { |
373 | rc = lgetfilecon(fileName, &con); | 382 | rc = lgetfilecon(fileName, &con); |
@@ -396,9 +405,9 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
396 | 405 | ||
397 | #if ENABLE_FEATURE_FIND_XDEV | 406 | #if ENABLE_FEATURE_FIND_XDEV |
398 | if (S_ISDIR(statbuf->st_mode)) { | 407 | if (S_ISDIR(statbuf->st_mode)) { |
399 | if (xdev_count) { | 408 | if (G.xdev_count) { |
400 | for (i = 0; i < xdev_count; i++) { | 409 | for (i = 0; i < G.xdev_count; i++) { |
401 | if (xdev_dev[i] == statbuf->st_dev) | 410 | if (G.xdev_dev[i] == statbuf->st_dev) |
402 | goto found; | 411 | goto found; |
403 | } | 412 | } |
404 | return SKIP; | 413 | return SKIP; |
@@ -406,9 +415,9 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
406 | } | 415 | } |
407 | } | 416 | } |
408 | #endif | 417 | #endif |
409 | i = exec_actions(actions, fileName, statbuf); | 418 | i = exec_actions(G.actions, fileName, statbuf); |
410 | /* Had no explicit -print[0] or -exec? then print */ | 419 | /* Had no explicit -print[0] or -exec? then print */ |
411 | if ((i & TRUE) && need_print) | 420 | if ((i & TRUE) && G.need_print) |
412 | puts(fileName); | 421 | puts(fileName); |
413 | 422 | ||
414 | #if ENABLE_FEATURE_FIND_MAXDEPTH | 423 | #if ENABLE_FEATURE_FIND_MAXDEPTH |
@@ -443,7 +452,7 @@ static int find_type(const char *type) | |||
443 | else if (*type == 's') | 452 | else if (*type == 's') |
444 | mask = S_IFSOCK; | 453 | mask = S_IFSOCK; |
445 | 454 | ||
446 | if (mask == 0 || *(type + 1) != '\0') | 455 | if (mask == 0 || type[1] != '\0') |
447 | bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type"); | 456 | bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type"); |
448 | 457 | ||
449 | return mask; | 458 | return mask; |
@@ -464,15 +473,15 @@ static const char* plus_minus_num(const char* str) | |||
464 | static action*** parse_params(char **argv) | 473 | static action*** parse_params(char **argv) |
465 | { | 474 | { |
466 | enum { | 475 | enum { |
467 | PARM_a , | 476 | PARM_a , |
468 | PARM_o , | 477 | PARM_o , |
469 | IF_FEATURE_FIND_NOT( PARM_char_not ,) | 478 | IF_FEATURE_FIND_NOT( PARM_char_not ,) |
470 | #if ENABLE_DESKTOP | 479 | #if ENABLE_DESKTOP |
471 | PARM_and , | 480 | PARM_and , |
472 | PARM_or , | 481 | PARM_or , |
473 | IF_FEATURE_FIND_NOT( PARM_not ,) | 482 | IF_FEATURE_FIND_NOT( PARM_not ,) |
474 | #endif | 483 | #endif |
475 | PARM_print , | 484 | PARM_print , |
476 | IF_FEATURE_FIND_PRINT0( PARM_print0 ,) | 485 | IF_FEATURE_FIND_PRINT0( PARM_print0 ,) |
477 | IF_FEATURE_FIND_DEPTH( PARM_depth ,) | 486 | IF_FEATURE_FIND_DEPTH( PARM_depth ,) |
478 | IF_FEATURE_FIND_PRUNE( PARM_prune ,) | 487 | IF_FEATURE_FIND_PRUNE( PARM_prune ,) |
@@ -480,8 +489,8 @@ static action*** parse_params(char **argv) | |||
480 | IF_FEATURE_FIND_EXEC( PARM_exec ,) | 489 | IF_FEATURE_FIND_EXEC( PARM_exec ,) |
481 | IF_FEATURE_FIND_PAREN( PARM_char_brace,) | 490 | IF_FEATURE_FIND_PAREN( PARM_char_brace,) |
482 | /* All options starting from here require argument */ | 491 | /* All options starting from here require argument */ |
483 | PARM_name , | 492 | PARM_name , |
484 | PARM_iname , | 493 | PARM_iname , |
485 | IF_FEATURE_FIND_PATH( PARM_path ,) | 494 | IF_FEATURE_FIND_PATH( PARM_path ,) |
486 | IF_FEATURE_FIND_REGEX( PARM_regex ,) | 495 | IF_FEATURE_FIND_REGEX( PARM_regex ,) |
487 | IF_FEATURE_FIND_TYPE( PARM_type ,) | 496 | IF_FEATURE_FIND_TYPE( PARM_type ,) |
@@ -604,21 +613,21 @@ static action*** parse_params(char **argv) | |||
604 | 613 | ||
605 | /* --- Tests and actions --- */ | 614 | /* --- Tests and actions --- */ |
606 | else if (parm == PARM_print) { | 615 | else if (parm == PARM_print) { |
607 | need_print = 0; | 616 | G.need_print = 0; |
608 | /* GNU find ignores '!' here: "find ! -print" */ | 617 | /* GNU find ignores '!' here: "find ! -print" */ |
609 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | 618 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) |
610 | (void) ALLOC_ACTION(print); | 619 | (void) ALLOC_ACTION(print); |
611 | } | 620 | } |
612 | #if ENABLE_FEATURE_FIND_PRINT0 | 621 | #if ENABLE_FEATURE_FIND_PRINT0 |
613 | else if (parm == PARM_print0) { | 622 | else if (parm == PARM_print0) { |
614 | need_print = 0; | 623 | G.need_print = 0; |
615 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | 624 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) |
616 | (void) ALLOC_ACTION(print0); | 625 | (void) ALLOC_ACTION(print0); |
617 | } | 626 | } |
618 | #endif | 627 | #endif |
619 | #if ENABLE_FEATURE_FIND_DEPTH | 628 | #if ENABLE_FEATURE_FIND_DEPTH |
620 | else if (parm == PARM_depth) { | 629 | else if (parm == PARM_depth) { |
621 | recurse_flags |= ACTION_DEPTHFIRST; | 630 | G.recurse_flags |= ACTION_DEPTHFIRST; |
622 | } | 631 | } |
623 | #endif | 632 | #endif |
624 | #if ENABLE_FEATURE_FIND_PRUNE | 633 | #if ENABLE_FEATURE_FIND_PRUNE |
@@ -629,8 +638,8 @@ static action*** parse_params(char **argv) | |||
629 | #endif | 638 | #endif |
630 | #if ENABLE_FEATURE_FIND_DELETE | 639 | #if ENABLE_FEATURE_FIND_DELETE |
631 | else if (parm == PARM_delete) { | 640 | else if (parm == PARM_delete) { |
632 | need_print = 0; | 641 | G.need_print = 0; |
633 | recurse_flags |= ACTION_DEPTHFIRST; | 642 | G.recurse_flags |= ACTION_DEPTHFIRST; |
634 | (void) ALLOC_ACTION(delete); | 643 | (void) ALLOC_ACTION(delete); |
635 | } | 644 | } |
636 | #endif | 645 | #endif |
@@ -638,7 +647,7 @@ static action*** parse_params(char **argv) | |||
638 | else if (parm == PARM_exec) { | 647 | else if (parm == PARM_exec) { |
639 | int i; | 648 | int i; |
640 | action_exec *ap; | 649 | action_exec *ap; |
641 | need_print = 0; | 650 | G.need_print = 0; |
642 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | 651 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) |
643 | ap = ALLOC_ACTION(exec); | 652 | ap = ALLOC_ACTION(exec); |
644 | ap->exec_argv = ++argv; /* first arg after -exec */ | 653 | ap->exec_argv = ++argv; /* first arg after -exec */ |
@@ -846,6 +855,8 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | |||
846 | #define minmaxdepth NULL | 855 | #define minmaxdepth NULL |
847 | #endif | 856 | #endif |
848 | 857 | ||
858 | INIT_G(); | ||
859 | |||
849 | for (firstopt = 1; firstopt < argc; firstopt++) { | 860 | for (firstopt = 1; firstopt < argc; firstopt++) { |
850 | if (argv[firstopt][0] == '-') | 861 | if (argv[firstopt][0] == '-') |
851 | break; | 862 | break; |
@@ -873,21 +884,21 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | |||
873 | while ((arg = argp[0])) { | 884 | while ((arg = argp[0])) { |
874 | int opt = index_in_strings(options, arg); | 885 | int opt = index_in_strings(options, arg); |
875 | if (opt == OPT_FOLLOW) { | 886 | if (opt == OPT_FOLLOW) { |
876 | recurse_flags |= ACTION_FOLLOWLINKS; | 887 | G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; |
877 | argp[0] = (char*)"-a"; | 888 | argp[0] = (char*)"-a"; |
878 | } | 889 | } |
879 | #if ENABLE_FEATURE_FIND_XDEV | 890 | #if ENABLE_FEATURE_FIND_XDEV |
880 | if (opt == OPT_XDEV) { | 891 | if (opt == OPT_XDEV) { |
881 | struct stat stbuf; | 892 | struct stat stbuf; |
882 | if (!xdev_count) { | 893 | if (!G.xdev_count) { |
883 | xdev_count = firstopt - 1; | 894 | G.xdev_count = firstopt - 1; |
884 | xdev_dev = xmalloc(xdev_count * sizeof(dev_t)); | 895 | G.xdev_dev = xmalloc(G.xdev_count * sizeof(dev_t)); |
885 | for (i = 1; i < firstopt; i++) { | 896 | for (i = 1; i < firstopt; i++) { |
886 | /* not xstat(): shouldn't bomb out on | 897 | /* not xstat(): shouldn't bomb out on |
887 | * "find not_exist exist -xdev" */ | 898 | * "find not_exist exist -xdev" */ |
888 | if (stat(argv[i], &stbuf)) | 899 | if (stat(argv[i], &stbuf)) |
889 | stbuf.st_dev = -1L; | 900 | stbuf.st_dev = -1L; |
890 | xdev_dev[i-1] = stbuf.st_dev; | 901 | G.xdev_dev[i-1] = stbuf.st_dev; |
891 | } | 902 | } |
892 | } | 903 | } |
893 | argp[0] = (char*)"-a"; | 904 | argp[0] = (char*)"-a"; |
@@ -906,11 +917,11 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | |||
906 | argp++; | 917 | argp++; |
907 | } | 918 | } |
908 | 919 | ||
909 | actions = parse_params(&argv[firstopt]); | 920 | G.actions = parse_params(&argv[firstopt]); |
910 | 921 | ||
911 | for (i = 1; i < firstopt; i++) { | 922 | for (i = 1; i < firstopt; i++) { |
912 | if (!recursive_action(argv[i], | 923 | if (!recursive_action(argv[i], |
913 | recurse_flags, /* flags */ | 924 | G.recurse_flags,/* flags */ |
914 | fileAction, /* file action */ | 925 | fileAction, /* file action */ |
915 | fileAction, /* dir action */ | 926 | fileAction, /* dir action */ |
916 | #if ENABLE_FEATURE_FIND_MAXDEPTH | 927 | #if ENABLE_FEATURE_FIND_MAXDEPTH |
diff --git a/include/libbb.h b/include/libbb.h index 8ecde5b4b..a02355cc5 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -286,7 +286,9 @@ enum { | |||
286 | ACTION_DEPTHFIRST = (1 << 3), | 286 | ACTION_DEPTHFIRST = (1 << 3), |
287 | /*ACTION_REVERSE = (1 << 4), - unused */ | 287 | /*ACTION_REVERSE = (1 << 4), - unused */ |
288 | ACTION_QUIET = (1 << 5), | 288 | ACTION_QUIET = (1 << 5), |
289 | ACTION_DANGLING_OK = (1 << 6), | ||
289 | }; | 290 | }; |
291 | typedef uint8_t recurse_flags_t; | ||
290 | extern int recursive_action(const char *fileName, unsigned flags, | 292 | extern int recursive_action(const char *fileName, unsigned flags, |
291 | int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), | 293 | int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), |
292 | int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), | 294 | int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), |
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c index 3ec596a35..57262cd43 100644 --- a/libbb/recursive_action.c +++ b/libbb/recursive_action.c | |||
@@ -48,7 +48,7 @@ static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM, | |||
48 | * into that directory, instead recursive_action() returns 0 (if FALSE) | 48 | * into that directory, instead recursive_action() returns 0 (if FALSE) |
49 | * or 1 (if SKIP) | 49 | * or 1 (if SKIP) |
50 | * | 50 | * |
51 | * followLinks=0/1 differs mainly in handling of links to dirs. | 51 | * ACTION_FOLLOWLINKS mainly controls handling of links to dirs. |
52 | * 0: lstat(statbuf). Calls fileAction on link name even if points to dir. | 52 | * 0: lstat(statbuf). Calls fileAction on link name even if points to dir. |
53 | * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. | 53 | * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. |
54 | */ | 54 | */ |
@@ -61,6 +61,7 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
61 | unsigned depth) | 61 | unsigned depth) |
62 | { | 62 | { |
63 | struct stat statbuf; | 63 | struct stat statbuf; |
64 | unsigned follow; | ||
64 | int status; | 65 | int status; |
65 | DIR *dir; | 66 | DIR *dir; |
66 | struct dirent *next; | 67 | struct dirent *next; |
@@ -68,14 +69,22 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
68 | if (!fileAction) fileAction = true_action; | 69 | if (!fileAction) fileAction = true_action; |
69 | if (!dirAction) dirAction = true_action; | 70 | if (!dirAction) dirAction = true_action; |
70 | 71 | ||
71 | status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */ | 72 | follow = ACTION_FOLLOWLINKS; |
72 | if (!depth) | 73 | if (depth == 0) |
73 | status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; | 74 | follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; |
74 | status = ((flags & status) ? stat : lstat)(fileName, &statbuf); | 75 | follow &= flags; |
76 | status = (follow ? stat : lstat)(fileName, &statbuf); | ||
75 | if (status < 0) { | 77 | if (status < 0) { |
76 | #ifdef DEBUG_RECURS_ACTION | 78 | #ifdef DEBUG_RECURS_ACTION |
77 | bb_error_msg("status=%d flags=%x", status, flags); | 79 | bb_error_msg("status=%d flags=%x", status, flags); |
78 | #endif | 80 | #endif |
81 | if ((flags & ACTION_DANGLING_OK) | ||
82 | && errno == ENOENT | ||
83 | && lstat(fileName, &statbuf) == 0 | ||
84 | ) { | ||
85 | /* Dangling link */ | ||
86 | return fileAction(fileName, &statbuf, userData, depth); | ||
87 | } | ||
79 | goto done_nak_warn; | 88 | goto done_nak_warn; |
80 | } | 89 | } |
81 | 90 | ||