find: add conditional support for -maxdepth and -regex

(needed for Linux 2.6.22-rc4 build)

-maxdepth:
# size busybox_old busybox_unstripped
   text    data     bss     dec     hex filename
 675622    2792   15728  694142   a977e busybox_old
 675770    2792   15728  694290   a9812 busybox_unstripped

-regex:
# size busybox_old busybox_unstripped
   text    data     bss     dec     hex filename
 675770    2792   15728  694290   a9812 busybox_old
 675894    2792   15728  694414   a988e busybox_unstripped
This commit is contained in:
Denis Vlasenko 2007-06-15 23:43:11 +00:00
parent d786cc5966
commit b941129ccb
3 changed files with 152 additions and 85 deletions

View File

@ -57,8 +57,14 @@ config FEATURE_FIND_XDEV
default y default y
depends on FIND depends on FIND
help help
This option will allow find to restrict searches to a single This option allows find to restrict searches to a single filesystem.
filesystem.
config FEATURE_FIND_MAXDEPTH
bool "Enable -maxdepth N option"
default y
depends on FIND
help
This option enables -maxdepth N option.
config FEATURE_FIND_NEWER config FEATURE_FIND_NEWER
bool "Enable -newer option for comparing file mtimes" bool "Enable -newer option for comparing file mtimes"
@ -149,7 +155,14 @@ config FEATURE_FIND_PATH
default y default y
depends on FIND depends on FIND
help help
The -path option matches whole pathnames instead of just filenames. The -path option matches whole pathname instead of just filename.
config FEATURE_FIND_REGEX
bool "Enable -regex: match pathname to regex"
default y
depends on FIND
help
The -regex option matches whole pathname against regular expression.
config GREP config GREP
bool "grep" bool "grep"

View File

@ -47,6 +47,9 @@
#include <fnmatch.h> #include <fnmatch.h>
#include "libbb.h" #include "libbb.h"
#if ENABLE_FEATURE_FIND_REGEX
#include "xregex.h"
#endif
/* This is a NOEXEC applet. Be very careful! */ /* This is a NOEXEC applet. Be very careful! */
@ -66,6 +69,8 @@ typedef struct {
#define ACTF(name) static int func_##name(const char *fileName, struct stat *statbuf, action_##name* ap) #define ACTF(name) static int func_##name(const char *fileName, struct stat *statbuf, action_##name* ap)
ACTS(print) ACTS(print)
ACTS(name, const char *pattern;) ACTS(name, const char *pattern;)
USE_FEATURE_FIND_PATH( ACTS(path, const char *pattern;))
USE_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;))
USE_FEATURE_FIND_PRINT0(ACTS(print0)) USE_FEATURE_FIND_PRINT0(ACTS(print0))
USE_FEATURE_FIND_TYPE( ACTS(type, int type_mask;)) USE_FEATURE_FIND_TYPE( ACTS(type, int type_mask;))
USE_FEATURE_FIND_PERM( ACTS(perm, char perm_char; mode_t perm_mask;)) USE_FEATURE_FIND_PERM( ACTS(perm, char perm_char; mode_t perm_mask;))
@ -80,7 +85,6 @@ USE_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;))
USE_FEATURE_FIND_SIZE( ACTS(size, off_t size;)) USE_FEATURE_FIND_SIZE( ACTS(size, off_t size;))
USE_FEATURE_FIND_PRUNE( ACTS(prune)) USE_FEATURE_FIND_PRUNE( ACTS(prune))
USE_FEATURE_FIND_DELETE(ACTS(delete)) USE_FEATURE_FIND_DELETE(ACTS(delete))
USE_FEATURE_FIND_PATH( ACTS(path, const char *pattern;))
static action ***actions; static action ***actions;
static bool need_print = 1; static bool need_print = 1;
@ -182,6 +186,25 @@ ACTF(name)
} }
return fnmatch(ap->pattern, tmp, FNM_PERIOD) == 0; return fnmatch(ap->pattern, tmp, FNM_PERIOD) == 0;
} }
#if ENABLE_FEATURE_FIND_PATH
ACTF(path)
{
return fnmatch(ap->pattern, fileName, 0) == 0;
}
#endif
#if ENABLE_FEATURE_FIND_REGEX
ACTF(regex)
{
regmatch_t match;
if (regexec(&ap->compiled_pattern, fileName, 1, &match, 0 /*eflags*/))
return 0; /* no match */
if (match.rm_so)
return 0; /* match doesn't start at pos 0 */
if (fileName[match.rm_eo])
return 0; /* match doesn't end exactly at end of pathname */
return 1;
}
#endif
#if ENABLE_FEATURE_FIND_TYPE #if ENABLE_FEATURE_FIND_TYPE
ACTF(type) ACTF(type)
{ {
@ -258,21 +281,18 @@ ACTF(exec)
return rc == 0; /* return 1 if exitcode 0 */ return rc == 0; /* return 1 if exitcode 0 */
} }
#endif #endif
#if ENABLE_FEATURE_FIND_USER #if ENABLE_FEATURE_FIND_USER
ACTF(user) ACTF(user)
{ {
return (statbuf->st_uid == ap->uid); return (statbuf->st_uid == ap->uid);
} }
#endif #endif
#if ENABLE_FEATURE_FIND_GROUP #if ENABLE_FEATURE_FIND_GROUP
ACTF(group) ACTF(group)
{ {
return (statbuf->st_gid == ap->gid); return (statbuf->st_gid == ap->gid);
} }
#endif #endif
#if ENABLE_FEATURE_FIND_PRINT0 #if ENABLE_FEATURE_FIND_PRINT0
ACTF(print0) ACTF(print0)
{ {
@ -280,20 +300,23 @@ ACTF(print0)
return TRUE; return TRUE;
} }
#endif #endif
ACTF(print) ACTF(print)
{ {
puts(fileName); puts(fileName);
return TRUE; return TRUE;
} }
#if ENABLE_FEATURE_FIND_PAREN #if ENABLE_FEATURE_FIND_PAREN
ACTF(paren) ACTF(paren)
{ {
return exec_actions(ap->subexpr, fileName, statbuf); return exec_actions(ap->subexpr, fileName, statbuf);
} }
#endif #endif
#if ENABLE_FEATURE_FIND_SIZE
ACTF(size)
{
return statbuf->st_size == ap->size;
}
#endif
#if ENABLE_FEATURE_FIND_PRUNE #if ENABLE_FEATURE_FIND_PRUNE
/* /*
* -prune: if -depth is not given, return true and do not descend * -prune: if -depth is not given, return true and do not descend
@ -306,7 +329,6 @@ ACTF(prune)
return SKIP + TRUE; return SKIP + TRUE;
} }
#endif #endif
#if ENABLE_FEATURE_FIND_DELETE #if ENABLE_FEATURE_FIND_DELETE
ACTF(delete) ACTF(delete)
{ {
@ -322,24 +344,16 @@ ACTF(delete)
} }
#endif #endif
#if ENABLE_FEATURE_FIND_PATH
ACTF(path)
{
return fnmatch(ap->pattern, fileName, 0) == 0;
}
#endif
#if ENABLE_FEATURE_FIND_SIZE static int fileAction(const char *fileName, struct stat *statbuf, void *userData, int depth)
ACTF(size)
{
return statbuf->st_size == ap->size;
}
#endif
static int fileAction(const char *fileName, struct stat *statbuf, void* junk, int depth)
{ {
int i; int i;
#if ENABLE_FEATURE_FIND_MAXDEPTH
int maxdepth = (int)(ptrdiff_t)userData;
if (depth > maxdepth) return SKIP;
#endif
#if ENABLE_FEATURE_FIND_XDEV #if ENABLE_FEATURE_FIND_XDEV
if (S_ISDIR(statbuf->st_mode) && xdev_count) { if (S_ISDIR(statbuf->st_mode) && xdev_count) {
for (i = 0; i < xdev_count; i++) { for (i = 0; i < xdev_count; i++) {
@ -404,6 +418,8 @@ static action*** parse_params(char **argv)
PARM_print , PARM_print ,
USE_FEATURE_FIND_PRINT0(PARM_print0 ,) USE_FEATURE_FIND_PRINT0(PARM_print0 ,)
PARM_name , PARM_name ,
USE_FEATURE_FIND_PATH( PARM_path ,)
USE_FEATURE_FIND_REGEX( PARM_regex ,)
USE_FEATURE_FIND_TYPE( PARM_type ,) USE_FEATURE_FIND_TYPE( PARM_type ,)
USE_FEATURE_FIND_PERM( PARM_perm ,) USE_FEATURE_FIND_PERM( PARM_perm ,)
USE_FEATURE_FIND_MTIME( PARM_mtime ,) USE_FEATURE_FIND_MTIME( PARM_mtime ,)
@ -418,7 +434,6 @@ static action*** parse_params(char **argv)
USE_FEATURE_FIND_SIZE( PARM_size ,) USE_FEATURE_FIND_SIZE( PARM_size ,)
USE_FEATURE_FIND_PRUNE( PARM_prune ,) USE_FEATURE_FIND_PRUNE( PARM_prune ,)
USE_FEATURE_FIND_DELETE(PARM_delete ,) USE_FEATURE_FIND_DELETE(PARM_delete ,)
USE_FEATURE_FIND_PATH( PARM_path ,)
#if ENABLE_DESKTOP #if ENABLE_DESKTOP
PARM_and , PARM_and ,
PARM_or , PARM_or ,
@ -433,6 +448,8 @@ static action*** parse_params(char **argv)
"-print" , "-print" ,
USE_FEATURE_FIND_PRINT0("-print0",) USE_FEATURE_FIND_PRINT0("-print0",)
"-name" , "-name" ,
USE_FEATURE_FIND_PATH( "-path" ,)
USE_FEATURE_FIND_REGEX( "-regex" ,)
USE_FEATURE_FIND_TYPE( "-type" ,) USE_FEATURE_FIND_TYPE( "-type" ,)
USE_FEATURE_FIND_PERM( "-perm" ,) USE_FEATURE_FIND_PERM( "-perm" ,)
USE_FEATURE_FIND_MTIME( "-mtime" ,) USE_FEATURE_FIND_MTIME( "-mtime" ,)
@ -447,7 +464,6 @@ static action*** parse_params(char **argv)
USE_FEATURE_FIND_SIZE( "-size" ,) USE_FEATURE_FIND_SIZE( "-size" ,)
USE_FEATURE_FIND_PRUNE( "-prune" ,) USE_FEATURE_FIND_PRUNE( "-prune" ,)
USE_FEATURE_FIND_DELETE("-delete",) USE_FEATURE_FIND_DELETE("-delete",)
USE_FEATURE_FIND_PATH( "-path" ,)
#if ENABLE_DESKTOP #if ENABLE_DESKTOP
"-and" , "-and" ,
"-or" , "-or" ,
@ -536,6 +552,24 @@ static action*** parse_params(char **argv)
ap = ALLOC_ACTION(name); ap = ALLOC_ACTION(name);
ap->pattern = arg1; ap->pattern = arg1;
} }
#if ENABLE_FEATURE_FIND_PATH
else if (parm == PARM_path) {
action_path *ap;
if (!*++argv)
bb_error_msg_and_die(bb_msg_requires_arg, arg);
ap = ALLOC_ACTION(path);
ap->pattern = arg1;
}
#endif
#if ENABLE_FEATURE_FIND_REGEX
else if (parm == PARM_regex) {
action_regex *ap;
if (!*++argv)
bb_error_msg_and_die(bb_msg_requires_arg, arg);
ap = ALLOC_ACTION(regex);
xregcomp(&ap->compiled_pattern, arg1, 0 /*cflags*/);
}
#endif
#if ENABLE_FEATURE_FIND_TYPE #if ENABLE_FEATURE_FIND_TYPE
else if (parm == PARM_type) { else if (parm == PARM_type) {
action_type *ap; action_type *ap;
@ -678,6 +712,15 @@ static action*** parse_params(char **argv)
argv = endarg; argv = endarg;
} }
#endif #endif
#if ENABLE_FEATURE_FIND_SIZE
else if (parm == PARM_size) {
action_size *ap;
if (!*++argv)
bb_error_msg_and_die(bb_msg_requires_arg, arg);
ap = ALLOC_ACTION(size);
ap->size = XATOOFF(arg1);
}
#endif
#if ENABLE_FEATURE_FIND_PRUNE #if ENABLE_FEATURE_FIND_PRUNE
else if (parm == PARM_prune) { else if (parm == PARM_prune) {
USE_FEATURE_FIND_NOT( invert_flag = 0; ) USE_FEATURE_FIND_NOT( invert_flag = 0; )
@ -691,26 +734,10 @@ static action*** parse_params(char **argv)
(void) ALLOC_ACTION(delete); (void) ALLOC_ACTION(delete);
} }
#endif #endif
#if ENABLE_FEATURE_FIND_PATH else {
else if (parm == PARM_path) { bb_error_msg("unrecognized: %s", arg);
action_path *ap;
if (!*++argv)
bb_error_msg_and_die(bb_msg_requires_arg, arg);
ap = ALLOC_ACTION(path);
ap->pattern = arg1;
}
#endif
#if ENABLE_FEATURE_FIND_SIZE
else if (parm == PARM_size) {
action_size *ap;
if (!*++argv)
bb_error_msg_and_die(bb_msg_requires_arg, arg);
ap = ALLOC_ACTION(size);
ap->size = XATOOFF(arg1);
}
#endif
else
bb_show_usage(); bb_show_usage();
}
argv++; argv++;
} }
return appp; return appp;
@ -721,15 +748,24 @@ static action*** parse_params(char **argv)
int find_main(int argc, char **argv); int find_main(int argc, char **argv);
int find_main(int argc, char **argv) int find_main(int argc, char **argv)
{ {
static const char * const options[] = { static const char *const options[] = {
"-follow", "-follow",
USE_FEATURE_FIND_XDEV( "-xdev", ) USE_FEATURE_FIND_XDEV( "-xdev" ,)
USE_FEATURE_FIND_MAXDEPTH("-maxdepth",)
NULL NULL
}; };
enum {
OPT_FOLLOW,
USE_FEATURE_FIND_XDEV( OPT_XDEV ,)
USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,)
};
char *arg; char *arg;
char **argp; char **argp;
int i, firstopt, status = EXIT_SUCCESS; int i, firstopt, status = EXIT_SUCCESS;
#if ENABLE_FEATURE_FIND_MAXDEPTH
int maxdepth = INT_MAX;
#endif
for (firstopt = 1; firstopt < argc; firstopt++) { for (firstopt = 1; firstopt < argc; firstopt++) {
if (argv[firstopt][0] == '-') if (argv[firstopt][0] == '-')
@ -750,19 +786,19 @@ USE_FEATURE_FIND_XDEV( "-xdev", )
/* All options always return true. They always take effect /* All options always return true. They always take effect
* rather than being processed only when their place in the * rather than being processed only when their place in the
* expression is reached. * expression is reached.
* We implement: -follow, -xdev * We implement: -follow, -xdev, -maxdepth
*/ */
/* Process options, and replace then with -a */ /* Process options, and replace then with -a */
/* (-a will be ignored by recursive parser later) */ /* (-a will be ignored by recursive parser later) */
argp = &argv[firstopt]; argp = &argv[firstopt];
while ((arg = argp[0])) { while ((arg = argp[0])) {
i = index_in_str_array(options, arg); int opt = index_in_str_array(options, arg);
if (i == 0) { /* -follow */ if (opt == OPT_FOLLOW) {
recurse_flags |= ACTION_FOLLOWLINKS; recurse_flags |= ACTION_FOLLOWLINKS;
argp[0] = (char*)"-a"; argp[0] = (char*)"-a";
} }
#if ENABLE_FEATURE_FIND_XDEV #if ENABLE_FEATURE_FIND_XDEV
else if (i == 1) { /* -xdev */ if (opt == OPT_XDEV) {
struct stat stbuf; struct stat stbuf;
if (!xdev_count) { if (!xdev_count) {
xdev_count = firstopt - 1; xdev_count = firstopt - 1;
@ -777,6 +813,16 @@ USE_FEATURE_FIND_XDEV( "-xdev", )
} }
argp[0] = (char*)"-a"; argp[0] = (char*)"-a";
} }
#endif
#if ENABLE_FEATURE_FIND_MAXDEPTH
if (opt == OPT_MAXDEPTH) {
if (!argp[1])
bb_show_usage();
maxdepth = xatoi_u(argp[1]);
argp[0] = (char*)"-a";
argp[1] = (char*)"-a";
argp++;
}
#endif #endif
argp++; argp++;
} }
@ -788,7 +834,11 @@ USE_FEATURE_FIND_XDEV( "-xdev", )
recurse_flags, /* flags */ recurse_flags, /* flags */
fileAction, /* file action */ fileAction, /* file action */
fileAction, /* dir action */ fileAction, /* dir action */
#if ENABLE_FEATURE_FIND_MAXDEPTH
(void*)maxdepth,/* user data */
#else
NULL, /* user data */ NULL, /* user data */
#endif
0)) /* depth */ 0)) /* depth */
status = EXIT_FAILURE; status = EXIT_FAILURE;
} }

View File

@ -943,46 +943,50 @@
"the current directory, default EXPRESSION is '-print'\n" \ "the current directory, default EXPRESSION is '-print'\n" \
"\nEXPRESSION may consist of:" \ "\nEXPRESSION may consist of:" \
"\n -follow Dereference symlinks" \ "\n -follow Dereference symlinks" \
USE_FEATURE_FIND_XDEV( \
"\n -xdev Don't descend directories on other filesystems") \
USE_FEATURE_FIND_MAXDEPTH( \
"\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" \
"\n tests/actions to command line arguments only") \
"\n -name PATTERN File name (leading directories removed) matches PATTERN" \ "\n -name PATTERN File name (leading directories removed) matches PATTERN" \
"\n -print Print (default and assumed)" \ "\n -print Print (default and assumed)" \
USE_FEATURE_FIND_PRINT0( \ USE_FEATURE_FIND_PRINT0( \
"\n -print0 Delimit output with null characters rather than" \ "\n -print0 Delimit output with null characters rather than" \
"\n newlines" \ "\n newlines") \
) USE_FEATURE_FIND_TYPE( \ USE_FEATURE_FIND_TYPE( \
"\n -type X Filetype matches X (where X is one of: f,d,l,b,c,...)" \ "\n -type X Filetype matches X (where X is one of: f,d,l,b,c,...)") \
) USE_FEATURE_FIND_PERM( \ USE_FEATURE_FIND_PERM( \
"\n -perm PERMS Permissions match any of (+NNN), all of (-NNN)," \ "\n -perm PERMS Permissions match any of (+NNN), all of (-NNN)," \
"\n or exactly (NNN)" \ "\n or exactly (NNN)") \
) USE_FEATURE_FIND_MTIME( \ USE_FEATURE_FIND_MTIME( \
"\n -mtime DAYS Modified time is greater than (+N), less than (-N)," \ "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," \
"\n or exactly (N) days" \ "\n or exactly (N) days") \
) USE_FEATURE_FIND_MMIN( \ USE_FEATURE_FIND_MMIN( \
"\n -mmin MINS Modified time is greater than (+N), less than (-N)," \ "\n -mmin MINS Modified time is greater than (+N), less than (-N)," \
"\n or exactly (N) minutes" \ "\n or exactly (N) minutes") \
) USE_FEATURE_FIND_NEWER( \ USE_FEATURE_FIND_NEWER( \
"\n -newer FILE Modified time is more recent than FILE's" \ "\n -newer FILE Modified time is more recent than FILE's") \
) USE_FEATURE_FIND_INUM( \ USE_FEATURE_FIND_INUM( \
"\n -inum N File has inode number N" \ "\n -inum N File has inode number N") \
) USE_FEATURE_FIND_EXEC( \ USE_FEATURE_FIND_EXEC( \
"\n -exec CMD Execute CMD with all instances of {} replaced by the" \ "\n -exec CMD Execute CMD with all instances of {} replaced by the" \
"\n files matching EXPRESSION" \ "\n files matching EXPRESSION") \
) USE_FEATURE_FIND_USER( \ USE_FEATURE_FIND_USER( \
"\n -user NAME File is owned by user NAME (numeric user ID allowed)" \ "\n -user NAME File is owned by user NAME (numeric user ID allowed)") \
) USE_FEATURE_FIND_GROUP( \ USE_FEATURE_FIND_GROUP( \
"\n -group NAME File belongs to group NAME (numeric group ID allowed)" \ "\n -group NAME File belongs to group NAME (numeric group ID allowed)") \
) USE_FEATURE_FIND_DEPTH( \ USE_FEATURE_FIND_DEPTH( \
"\n -depth Process directory after traversing it" \ "\n -depth Process directory after traversing it") \
) USE_FEATURE_FIND_SIZE( \ USE_FEATURE_FIND_SIZE( \
"\n -size N File size is N" \ "\n -size N File size is N") \
) USE_FEATURE_FIND_PRUNE( \ USE_FEATURE_FIND_PRUNE( \
"\n -prune Stop traversing current subtree" \ "\n -prune Stop traversing current subtree") \
) USE_FEATURE_FIND_DELETE( \ USE_FEATURE_FIND_DELETE( \
"\n -delete Delete files, turns on -depth option" \ "\n -delete Delete files, turns on -depth option") \
) USE_FEATURE_FIND_PATH( \ USE_FEATURE_FIND_PATH( \
"\n -path Path matches PATTERN" \ "\n -path Path matches PATTERN") \
) USE_FEATURE_FIND_PAREN( \ USE_FEATURE_FIND_PAREN( \
"\n (EXPR) Group an expression" \ "\n (EXPR) Group an expression") \
)
#define find_example_usage \ #define find_example_usage \
"$ find / -name passwd\n" \ "$ find / -name passwd\n" \