aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--findutils/find.c79
-rw-r--r--include/libbb.h2
-rw-r--r--libbb/recursive_action.c19
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
65IF_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
66IF_FEATURE_FIND_XDEV(static int xdev_count;)
67
68typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC; 65typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC;
69 66
70typedef struct { 67typedef struct {
@@ -100,9 +97,21 @@ IF_FEATURE_FIND_DELETE( ACTS(delete))
100IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) 97IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;))
101IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) 98IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;))
102 99
103static action ***actions; 100struct globals {
104static bool need_print = 1; 101 IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;)
105static 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
108static unsigned count_subst(const char *str) 117static 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)
464static action*** parse_params(char **argv) 473static 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};
291typedef uint8_t recurse_flags_t;
290extern int recursive_action(const char *fileName, unsigned flags, 292extern 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