/* This is a NOEXEC applet. Be very careful! */
-IF_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
-IF_FEATURE_FIND_XDEV(static int xdev_count;)
-
typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC;
typedef struct {
IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;))
IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;))
-static action ***actions;
-static bool need_print = 1;
-static int recurse_flags = ACTION_RECURSE;
+struct globals {
+ IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;)
+ IF_FEATURE_FIND_XDEV(int xdev_count;)
+ action ***actions;
+ bool need_print;
+ recurse_flags_t recurse_flags;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define INIT_G() do { \
+ struct G_sizecheck { \
+ char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
+ }; \
+ G.need_print = 1; \
+ G.recurse_flags = ACTION_RECURSE; \
+} while (0)
#if ENABLE_FEATURE_FIND_EXEC
static unsigned count_subst(const char *str)
security_context_t con;
int rc;
- if (recurse_flags & ACTION_FOLLOWLINKS) {
+ if (G.recurse_flags & ACTION_FOLLOWLINKS) {
rc = getfilecon(fileName, &con);
} else {
rc = lgetfilecon(fileName, &con);
#if ENABLE_FEATURE_FIND_XDEV
if (S_ISDIR(statbuf->st_mode)) {
- if (xdev_count) {
- for (i = 0; i < xdev_count; i++) {
- if (xdev_dev[i] == statbuf->st_dev)
+ if (G.xdev_count) {
+ for (i = 0; i < G.xdev_count; i++) {
+ if (G.xdev_dev[i] == statbuf->st_dev)
goto found;
}
return SKIP;
}
}
#endif
- i = exec_actions(actions, fileName, statbuf);
+ i = exec_actions(G.actions, fileName, statbuf);
/* Had no explicit -print[0] or -exec? then print */
- if ((i & TRUE) && need_print)
+ if ((i & TRUE) && G.need_print)
puts(fileName);
#if ENABLE_FEATURE_FIND_MAXDEPTH
else if (*type == 's')
mask = S_IFSOCK;
- if (mask == 0 || *(type + 1) != '\0')
+ if (mask == 0 || type[1] != '\0')
bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
return mask;
static action*** parse_params(char **argv)
{
enum {
- PARM_a ,
- PARM_o ,
- IF_FEATURE_FIND_NOT( PARM_char_not ,)
+ PARM_a ,
+ PARM_o ,
+ IF_FEATURE_FIND_NOT( PARM_char_not ,)
#if ENABLE_DESKTOP
- PARM_and ,
- PARM_or ,
+ PARM_and ,
+ PARM_or ,
IF_FEATURE_FIND_NOT( PARM_not ,)
#endif
- PARM_print ,
+ PARM_print ,
IF_FEATURE_FIND_PRINT0( PARM_print0 ,)
IF_FEATURE_FIND_DEPTH( PARM_depth ,)
IF_FEATURE_FIND_PRUNE( PARM_prune ,)
IF_FEATURE_FIND_EXEC( PARM_exec ,)
IF_FEATURE_FIND_PAREN( PARM_char_brace,)
/* All options starting from here require argument */
- PARM_name ,
- PARM_iname ,
+ PARM_name ,
+ PARM_iname ,
IF_FEATURE_FIND_PATH( PARM_path ,)
IF_FEATURE_FIND_REGEX( PARM_regex ,)
IF_FEATURE_FIND_TYPE( PARM_type ,)
/* --- Tests and actions --- */
else if (parm == PARM_print) {
- need_print = 0;
+ G.need_print = 0;
/* GNU find ignores '!' here: "find ! -print" */
IF_FEATURE_FIND_NOT( invert_flag = 0; )
(void) ALLOC_ACTION(print);
}
#if ENABLE_FEATURE_FIND_PRINT0
else if (parm == PARM_print0) {
- need_print = 0;
+ G.need_print = 0;
IF_FEATURE_FIND_NOT( invert_flag = 0; )
(void) ALLOC_ACTION(print0);
}
#endif
#if ENABLE_FEATURE_FIND_DEPTH
else if (parm == PARM_depth) {
- recurse_flags |= ACTION_DEPTHFIRST;
+ G.recurse_flags |= ACTION_DEPTHFIRST;
}
#endif
#if ENABLE_FEATURE_FIND_PRUNE
#endif
#if ENABLE_FEATURE_FIND_DELETE
else if (parm == PARM_delete) {
- need_print = 0;
- recurse_flags |= ACTION_DEPTHFIRST;
+ G.need_print = 0;
+ G.recurse_flags |= ACTION_DEPTHFIRST;
(void) ALLOC_ACTION(delete);
}
#endif
else if (parm == PARM_exec) {
int i;
action_exec *ap;
- need_print = 0;
+ G.need_print = 0;
IF_FEATURE_FIND_NOT( invert_flag = 0; )
ap = ALLOC_ACTION(exec);
ap->exec_argv = ++argv; /* first arg after -exec */
#define minmaxdepth NULL
#endif
+ INIT_G();
+
for (firstopt = 1; firstopt < argc; firstopt++) {
if (argv[firstopt][0] == '-')
break;
while ((arg = argp[0])) {
int opt = index_in_strings(options, arg);
if (opt == OPT_FOLLOW) {
- recurse_flags |= ACTION_FOLLOWLINKS;
+ G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
argp[0] = (char*)"-a";
}
#if ENABLE_FEATURE_FIND_XDEV
if (opt == OPT_XDEV) {
struct stat stbuf;
- if (!xdev_count) {
- xdev_count = firstopt - 1;
- xdev_dev = xmalloc(xdev_count * sizeof(dev_t));
+ if (!G.xdev_count) {
+ G.xdev_count = firstopt - 1;
+ G.xdev_dev = xmalloc(G.xdev_count * sizeof(dev_t));
for (i = 1; i < firstopt; i++) {
/* not xstat(): shouldn't bomb out on
* "find not_exist exist -xdev" */
if (stat(argv[i], &stbuf))
stbuf.st_dev = -1L;
- xdev_dev[i-1] = stbuf.st_dev;
+ G.xdev_dev[i-1] = stbuf.st_dev;
}
}
argp[0] = (char*)"-a";
argp++;
}
- actions = parse_params(&argv[firstopt]);
+ G.actions = parse_params(&argv[firstopt]);
for (i = 1; i < firstopt; i++) {
if (!recursive_action(argv[i],
- recurse_flags, /* flags */
+ G.recurse_flags,/* flags */
fileAction, /* file action */
fileAction, /* dir action */
#if ENABLE_FEATURE_FIND_MAXDEPTH
* into that directory, instead recursive_action() returns 0 (if FALSE)
* or 1 (if SKIP)
*
- * followLinks=0/1 differs mainly in handling of links to dirs.
+ * ACTION_FOLLOWLINKS mainly controls handling of links to dirs.
* 0: lstat(statbuf). Calls fileAction on link name even if points to dir.
* 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir.
*/
unsigned depth)
{
struct stat statbuf;
+ unsigned follow;
int status;
DIR *dir;
struct dirent *next;
if (!fileAction) fileAction = true_action;
if (!dirAction) dirAction = true_action;
- status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */
- if (!depth)
- status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
- status = ((flags & status) ? stat : lstat)(fileName, &statbuf);
+ follow = ACTION_FOLLOWLINKS;
+ if (depth == 0)
+ follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
+ follow &= flags;
+ status = (follow ? stat : lstat)(fileName, &statbuf);
if (status < 0) {
#ifdef DEBUG_RECURS_ACTION
bb_error_msg("status=%d flags=%x", status, flags);
#endif
+ if ((flags & ACTION_DANGLING_OK)
+ && errno == ENOENT
+ && lstat(fileName, &statbuf) == 0
+ ) {
+ /* Dangling link */
+ return fileAction(fileName, &statbuf, userData, depth);
+ }
goto done_nak_warn;
}