Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/findutils/find.c

    r1765 r2725  
    88 *  Matt Kraai <kraai@alumni.carnegiemellon.edu>.
    99 *
    10  * Licensed under the GPL version 2, see the file LICENSE in this tarball.
     10 * Licensed under GPLv2, see file LICENSE in this source tree.
    1111 */
    1212
     
    5454 */
    5555
     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
     61//config:   bool "find"
     62//config:   default y
     63//config:   help
     64//config:     find is used to search your system to find specified files.
     65//config:
     66//config:config FEATURE_FIND_PRINT0
     67//config:   bool "Enable -print0: NUL-terminated output"
     68//config:   default y
     69//config:   depends on FIND
     70//config:   help
     71//config:     Causes output names to be separated by a NUL character
     72//config:     rather than a newline. This allows names that contain
     73//config:     newlines and other whitespace to be more easily
     74//config:     interpreted by other programs.
     75//config:
     76//config:config FEATURE_FIND_MTIME
     77//config:   bool "Enable -mtime: modified time matching"
     78//config:   default y
     79//config:   depends on FIND
     80//config:   help
     81//config:     Allow searching based on the modification time of
     82//config:     files, in days.
     83//config:
     84//config:config FEATURE_FIND_MMIN
     85//config:   bool "Enable -mmin: modified time matching by minutes"
     86//config:   default y
     87//config:   depends on FIND
     88//config:   help
     89//config:     Allow searching based on the modification time of
     90//config:     files, in minutes.
     91//config:
     92//config:config FEATURE_FIND_PERM
     93//config:   bool "Enable -perm: permissions matching"
     94//config:   default y
     95//config:   depends on FIND
     96//config:   help
     97//config:     Enable searching based on file permissions.
     98//config:
     99//config:config FEATURE_FIND_TYPE
     100//config:   bool "Enable -type: file type matching (file/dir/link/...)"
     101//config:   default y
     102//config:   depends on FIND
     103//config:   help
     104//config:     Enable searching based on file type (file,
     105//config:     directory, socket, device, etc.).
     106//config:
     107//config:config FEATURE_FIND_XDEV
     108//config:   bool "Enable -xdev: 'stay in filesystem'"
     109//config:   default y
     110//config:   depends on FIND
     111//config:   help
     112//config:     This option allows find to restrict searches to a single filesystem.
     113//config:
     114//config:config FEATURE_FIND_MAXDEPTH
     115//config:   bool "Enable -maxdepth N"
     116//config:   default y
     117//config:   depends on FIND
     118//config:   help
     119//config:     This option enables -maxdepth N option.
     120//config:
     121//config:config FEATURE_FIND_NEWER
     122//config:   bool "Enable -newer: compare file modification times"
     123//config:   default y
     124//config:   depends on FIND
     125//config:   help
     126//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.
     128//config:
     129//config:config FEATURE_FIND_INUM
     130//config:   bool "Enable -inum: inode number matching"
     131//config:   default y
     132//config:   depends on FIND
     133//config:   help
     134//config:     Support the 'find -inum' option for searching by inode number.
     135//config:
     136//config:config FEATURE_FIND_EXEC
     137//config:   bool "Enable -exec: execute commands"
     138//config:   default y
     139//config:   depends on FIND
     140//config:   help
     141//config:     Support the 'find -exec' option for executing commands based upon
     142//config:     the files matched.
     143//config:
     144//config:config FEATURE_FIND_USER
     145//config:   bool "Enable -user: username/uid matching"
     146//config:   default y
     147//config:   depends on FIND
     148//config:   help
     149//config:     Support the 'find -user' option for searching by username or uid.
     150//config:
     151//config:config FEATURE_FIND_GROUP
     152//config:   bool "Enable -group: group/gid matching"
     153//config:   default y
     154//config:   depends on FIND
     155//config:   help
     156//config:     Support the 'find -group' option for searching by group name or gid.
     157//config:
     158//config:config FEATURE_FIND_NOT
     159//config:   bool "Enable the 'not' (!) operator"
     160//config:   default y
     161//config:   depends on FIND
     162//config:   help
     163//config:     Support the '!' operator to invert the test results.
     164//config:     If 'Enable full-blown desktop' is enabled, then will also support
     165//config:     the non-POSIX notation '-not'.
     166//config:
     167//config:config FEATURE_FIND_DEPTH
     168//config:   bool "Enable -depth"
     169//config:   default y
     170//config:   depends on FIND
     171//config:   help
     172//config:     Process each directory's contents before the directory itself.
     173//config:
     174//config:config FEATURE_FIND_PAREN
     175//config:   bool "Enable parens in options"
     176//config:   default y
     177//config:   depends on FIND
     178//config:   help
     179//config:     Enable usage of parens '(' to specify logical order of arguments.
     180//config:
     181//config:config FEATURE_FIND_SIZE
     182//config:   bool "Enable -size: file size matching"
     183//config:   default y
     184//config:   depends on FIND
     185//config:   help
     186//config:     Support the 'find -size' option for searching by file size.
     187//config:
     188//config:config FEATURE_FIND_PRUNE
     189//config:   bool "Enable -prune: exclude subdirectories"
     190//config:   default y
     191//config:   depends on FIND
     192//config:   help
     193//config:     If the file is a directory, dont descend into it. Useful for
     194//config:     exclusion .svn and CVS directories.
     195//config:
     196//config:config FEATURE_FIND_DELETE
     197//config:   bool "Enable -delete: delete files/dirs"
     198//config:   default y
     199//config:   depends on FIND && FEATURE_FIND_DEPTH
     200//config:   help
     201//config:     Support the 'find -delete' option for deleting files and directories.
     202//config:     WARNING: This option can do much harm if used wrong. Busybox will not
     203//config:     try to protect the user from doing stupid things. Use with care.
     204//config:
     205//config:config FEATURE_FIND_PATH
     206//config:   bool "Enable -path: match pathname with shell pattern"
     207//config:   default y
     208//config:   depends on FIND
     209//config:   help
     210//config:     The -path option matches whole pathname instead of just filename.
     211//config:
     212//config:config FEATURE_FIND_REGEX
     213//config:   bool "Enable -regex: match pathname with regex"
     214//config:   default y
     215//config:   depends on FIND
     216//config:   help
     217//config:     The -regex option matches whole pathname against regular expression.
     218//config:
     219//config:config FEATURE_FIND_CONTEXT
     220//config:   bool "Enable -context: security context matching"
     221//config:   default n
     222//config:   depends on FIND && SELINUX
     223//config:   help
     224//config:     Support the 'find -context' option for matching security context.
     225//config:
     226//config:config FEATURE_FIND_LINKS
     227//config:   bool "Enable -links: link count matching"
     228//config:   default y
     229//config:   depends on FIND
     230//config:   help
     231//config:     Support the 'find -links' option for matching number of links.
     232
    56233#include <fnmatch.h>
    57234#include "libbb.h"
     
    63240
    64241
    65 USE_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
    66 USE_FEATURE_FIND_XDEV(static int xdev_count;)
    67 
    68 typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *);
     242typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC;
    69243
    70244typedef struct {
     
    74248#endif
    75249} action;
    76 #define ACTS(name, arg...) typedef struct { action a; arg; } action_##name;
    77 #define ACTF(name)         static int func_##name(const char *fileName, struct stat *statbuf, action_##name* ap)
    78                          ACTS(print)
    79                          ACTS(name,  const char *pattern;)
    80 USE_FEATURE_FIND_PATH(   ACTS(path,  const char *pattern;))
    81 USE_FEATURE_FIND_REGEX(  ACTS(regex, regex_t compiled_pattern;))
    82 USE_FEATURE_FIND_PRINT0( ACTS(print0))
    83 USE_FEATURE_FIND_TYPE(   ACTS(type,  int type_mask;))
    84 USE_FEATURE_FIND_PERM(   ACTS(perm,  char perm_char; mode_t perm_mask;))
    85 USE_FEATURE_FIND_MTIME(  ACTS(mtime, char mtime_char; unsigned mtime_days;))
    86 USE_FEATURE_FIND_MMIN(   ACTS(mmin,  char mmin_char; unsigned mmin_mins;))
    87 USE_FEATURE_FIND_NEWER(  ACTS(newer, time_t newer_mtime;))
    88 USE_FEATURE_FIND_INUM(   ACTS(inum,  ino_t inode_num;))
    89 USE_FEATURE_FIND_USER(   ACTS(user,  uid_t uid;))
    90 USE_FEATURE_FIND_SIZE(   ACTS(size,  char size_char; off_t size;))
    91 USE_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;))
    92 USE_FEATURE_FIND_PAREN(  ACTS(paren, action ***subexpr;))
    93 USE_FEATURE_FIND_PRUNE(  ACTS(prune))
    94 USE_FEATURE_FIND_DELETE( ACTS(delete))
    95 USE_FEATURE_FIND_EXEC(   ACTS(exec,  char **exec_argv; unsigned *subst_count; int exec_argc;))
    96 USE_FEATURE_FIND_GROUP(  ACTS(group, gid_t gid;))
    97 
    98 static action ***actions;
    99 static bool need_print = 1;
    100 static int recurse_flags = ACTION_RECURSE;
     250
     251#define ACTS(name, ...) typedef struct { action a; __VA_ARGS__ } action_##name;
     252#define ACTF(name) \
     253    static int FAST_FUNC func_##name(const char *fileName UNUSED_PARAM, \
     254        const struct stat *statbuf UNUSED_PARAM, \
     255        action_##name* ap UNUSED_PARAM)
     256
     257                        ACTS(print)
     258                        ACTS(name,  const char *pattern; bool iname;)
     259IF_FEATURE_FIND_PATH(   ACTS(path,  const char *pattern;))
     260IF_FEATURE_FIND_REGEX(  ACTS(regex, regex_t compiled_pattern;))
     261IF_FEATURE_FIND_PRINT0( ACTS(print0))
     262IF_FEATURE_FIND_TYPE(   ACTS(type,  int type_mask;))
     263IF_FEATURE_FIND_PERM(   ACTS(perm,  char perm_char; mode_t perm_mask;))
     264IF_FEATURE_FIND_MTIME(  ACTS(mtime, char mtime_char; unsigned mtime_days;))
     265IF_FEATURE_FIND_MMIN(   ACTS(mmin,  char mmin_char; unsigned mmin_mins;))
     266IF_FEATURE_FIND_NEWER(  ACTS(newer, time_t newer_mtime;))
     267IF_FEATURE_FIND_INUM(   ACTS(inum,  ino_t inode_num;))
     268IF_FEATURE_FIND_USER(   ACTS(user,  uid_t uid;))
     269IF_FEATURE_FIND_SIZE(   ACTS(size,  char size_char; off_t size;))
     270IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;))
     271IF_FEATURE_FIND_PAREN(  ACTS(paren, action ***subexpr;))
     272IF_FEATURE_FIND_PRUNE(  ACTS(prune))
     273IF_FEATURE_FIND_DELETE( ACTS(delete))
     274IF_FEATURE_FIND_EXEC(   ACTS(exec,  char **exec_argv; unsigned *subst_count; int exec_argc;))
     275IF_FEATURE_FIND_GROUP(  ACTS(group, gid_t gid;))
     276IF_FEATURE_FIND_LINKS(  ACTS(links, char links_char; int links_count;))
     277
     278struct globals {
     279    IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;)
     280    IF_FEATURE_FIND_XDEV(int xdev_count;)
     281    action ***actions;
     282    bool need_print;
     283    recurse_flags_t recurse_flags;
     284} FIX_ALIASING;
     285#define G (*(struct globals*)&bb_common_bufsiz1)
     286#define INIT_G() do { \
     287    struct G_sizecheck { \
     288        char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
     289    }; \
     290    /* we have to zero it out because of NOEXEC */ \
     291    memset(&G, 0, offsetof(struct globals, need_print)); \
     292    G.need_print = 1; \
     293    G.recurse_flags = ACTION_RECURSE; \
     294} while (0)
    101295
    102296#if ENABLE_FEATURE_FIND_EXEC
     
    135329 */
    136330
    137 static int exec_actions(action ***appp, const char *fileName, struct stat *statbuf)
     331static int exec_actions(action ***appp, const char *fileName, const struct stat *statbuf)
    138332{
    139333    int cur_group;
     
    160354
    161355    cur_group = -1;
    162     while ((app = appp[++cur_group])) {
     356    while ((app = appp[++cur_group]) != NULL) {
    163357        rc &= ~TRUE; /* 'success' so far, clear TRUE bit */
    164358        cur_action = -1;
     
    182376{
    183377    const char *tmp = bb_basename(fileName);
    184     if (tmp != fileName && !*tmp) { /* "foo/bar/". Oh no... go back to 'b' */
     378    if (tmp != fileName && *tmp == '\0') {
     379        /* "foo/bar/". Oh no... go back to 'b' */
    185380        tmp--;
    186381        while (tmp != fileName && *--tmp != '/')
     
    189384            tmp++;
    190385    }
    191     return fnmatch(ap->pattern, tmp, FNM_PERIOD) == 0;
    192 }
     386    /* Was using FNM_PERIOD flag too,
     387     * but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it.
     388     * find -name '*foo' should match .foo too:
     389     */
     390    return fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)) == 0;
     391}
     392
    193393#if ENABLE_FEATURE_FIND_PATH
    194394ACTF(path)
     
    271471{
    272472    int i, rc;
     473#if ENABLE_USE_PORTABLE_CODE
     474    char **argv = alloca(sizeof(char*) * (ap->exec_argc + 1));
     475#else /* gcc 4.3.1 generates smaller code: */
    273476    char *argv[ap->exec_argc + 1];
     477#endif
    274478    for (i = 0; i < ap->exec_argc; i++)
    275479        argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName);
     
    278482    rc = spawn_and_wait(argv);
    279483    if (rc < 0)
    280         bb_perror_msg("%s", argv[0]);
     484        bb_simple_perror_msg(argv[0]);
    281485
    282486    i = 0;
     
    348552    }
    349553    if (rc < 0)
    350         bb_perror_msg("%s", fileName);
     554        bb_simple_perror_msg(fileName);
    351555    return TRUE;
    352556}
     
    358562    int rc;
    359563
    360     if (recurse_flags & ACTION_FOLLOWLINKS) {
     564    if (G.recurse_flags & ACTION_FOLLOWLINKS) {
    361565        rc = getfilecon(fileName, &con);
    362566    } else {
     
    370574}
    371575#endif
    372 
    373 
    374 static int fileAction(const char *fileName, struct stat *statbuf, void *userData, int depth)
    375 {
    376     int i;
     576#if ENABLE_FEATURE_FIND_LINKS
     577ACTF(links)
     578{
     579    switch(ap->links_char) {
     580    case '-' : return (statbuf->st_nlink <  ap->links_count);
     581    case '+' : return (statbuf->st_nlink >  ap->links_count);
     582    default:   return (statbuf->st_nlink == ap->links_count);
     583    }
     584}
     585#endif
     586
     587static int FAST_FUNC fileAction(const char *fileName,
     588        struct stat *statbuf,
     589        void *userData IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM),
     590        int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM))
     591{
     592    int r;
    377593#if ENABLE_FEATURE_FIND_MAXDEPTH
    378     int maxdepth = (int)(ptrdiff_t)userData;
    379 
    380     if (depth > maxdepth) return SKIP;
    381 #endif
    382 
     594#define minmaxdepth ((int*)userData)
     595
     596    if (depth < minmaxdepth[0])
     597        return TRUE; /* skip this, continue recursing */
     598    if (depth > minmaxdepth[1])
     599        return SKIP; /* stop recursing */
     600#endif
     601
     602    r = exec_actions(G.actions, fileName, statbuf);
     603    /* Had no explicit -print[0] or -exec? then print */
     604    if ((r & TRUE) && G.need_print)
     605        puts(fileName);
     606
     607#if ENABLE_FEATURE_FIND_MAXDEPTH
     608    if (S_ISDIR(statbuf->st_mode)) {
     609        if (depth == minmaxdepth[1])
     610            return SKIP;
     611    }
     612#endif
    383613#if ENABLE_FEATURE_FIND_XDEV
    384     if (S_ISDIR(statbuf->st_mode) && xdev_count) {
    385         for (i = 0; i < xdev_count; i++) {
    386             if (xdev_dev[i] == statbuf->st_dev)
    387                 break;
    388         }
    389         if (i == xdev_count)
     614    /* -xdev stops on mountpoints, but AFTER mountpoit itself
     615     * is processed as usual */
     616    if (S_ISDIR(statbuf->st_mode)) {
     617        if (G.xdev_count) {
     618            int i;
     619            for (i = 0; i < G.xdev_count; i++) {
     620                if (G.xdev_dev[i] == statbuf->st_dev)
     621                    goto found;
     622            }
    390623            return SKIP;
    391     }
    392 #endif
    393     i = exec_actions(actions, fileName, statbuf);
    394     /* Had no explicit -print[0] or -exec? then print */
    395     if ((i & TRUE) && need_print)
    396         puts(fileName);
     624 found: ;
     625        }
     626    }
     627#endif
     628
    397629    /* Cannot return 0: our caller, recursive_action(),
    398630     * will perror() and skip dirs (if called on dir) */
    399     return (i & SKIP) ? SKIP : TRUE;
     631    return (r & SKIP) ? SKIP : TRUE;
     632#undef minmaxdepth
    400633}
    401634
     
    421654        mask = S_IFSOCK;
    422655
    423     if (mask == 0 || *(type + 1) != '\0')
     656    if (mask == 0 || type[1] != '\0')
    424657        bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
    425658
     
    430663#if ENABLE_FEATURE_FIND_PERM \
    431664 || ENABLE_FEATURE_FIND_MTIME || ENABLE_FEATURE_FIND_MMIN \
    432  || ENABLE_FEATURE_FIND_SIZE
     665 || ENABLE_FEATURE_FIND_SIZE  || ENABLE_FEATURE_FIND_LINKS
    433666static const char* plus_minus_num(const char* str)
    434667{
     
    442675{
    443676    enum {
    444                              PARM_a         ,
    445                              PARM_o         ,
    446     USE_FEATURE_FIND_NOT(    PARM_char_not  ,)
     677                            PARM_a         ,
     678                            PARM_o         ,
     679    IF_FEATURE_FIND_NOT(    PARM_char_not  ,)
    447680#if ENABLE_DESKTOP
    448                              PARM_and       ,
    449                              PARM_or        ,
    450     USE_FEATURE_FIND_NOT(    PARM_not       ,)
    451 #endif
    452                              PARM_print     ,
    453     USE_FEATURE_FIND_PRINT0( PARM_print0    ,)
    454     USE_FEATURE_FIND_DEPTH(  PARM_depth     ,)
    455     USE_FEATURE_FIND_PRUNE(  PARM_prune     ,)
    456     USE_FEATURE_FIND_DELETE( PARM_delete    ,)
    457     USE_FEATURE_FIND_EXEC(   PARM_exec      ,)
    458     USE_FEATURE_FIND_PAREN(  PARM_char_brace,)
     681                            PARM_and       ,
     682                            PARM_or        ,
     683    IF_FEATURE_FIND_NOT(    PARM_not       ,)
     684#endif
     685                            PARM_print     ,
     686    IF_FEATURE_FIND_PRINT0( PARM_print0    ,)
     687    IF_FEATURE_FIND_DEPTH(  PARM_depth     ,)
     688    IF_FEATURE_FIND_PRUNE(  PARM_prune     ,)
     689    IF_FEATURE_FIND_DELETE( PARM_delete    ,)
     690    IF_FEATURE_FIND_EXEC(   PARM_exec      ,)
     691    IF_FEATURE_FIND_PAREN(  PARM_char_brace,)
    459692    /* All options starting from here require argument */
    460                              PARM_name      ,
    461     USE_FEATURE_FIND_PATH(   PARM_path      ,)
    462     USE_FEATURE_FIND_REGEX(  PARM_regex     ,)
    463     USE_FEATURE_FIND_TYPE(   PARM_type      ,)
    464     USE_FEATURE_FIND_PERM(   PARM_perm      ,)
    465     USE_FEATURE_FIND_MTIME(  PARM_mtime     ,)
    466     USE_FEATURE_FIND_MMIN(   PARM_mmin      ,)
    467     USE_FEATURE_FIND_NEWER(  PARM_newer     ,)
    468     USE_FEATURE_FIND_INUM(   PARM_inum      ,)
    469     USE_FEATURE_FIND_USER(   PARM_user      ,)
    470     USE_FEATURE_FIND_GROUP(  PARM_group     ,)
    471     USE_FEATURE_FIND_SIZE(   PARM_size      ,)
    472     USE_FEATURE_FIND_CONTEXT(PARM_context   ,)
     693                            PARM_name      ,
     694                            PARM_iname     ,
     695    IF_FEATURE_FIND_PATH(   PARM_path      ,)
     696    IF_FEATURE_FIND_REGEX(  PARM_regex     ,)
     697    IF_FEATURE_FIND_TYPE(   PARM_type      ,)
     698    IF_FEATURE_FIND_PERM(   PARM_perm      ,)
     699    IF_FEATURE_FIND_MTIME(  PARM_mtime     ,)
     700    IF_FEATURE_FIND_MMIN(   PARM_mmin      ,)
     701    IF_FEATURE_FIND_NEWER(  PARM_newer     ,)
     702    IF_FEATURE_FIND_INUM(   PARM_inum      ,)
     703    IF_FEATURE_FIND_USER(   PARM_user      ,)
     704    IF_FEATURE_FIND_GROUP(  PARM_group     ,)
     705    IF_FEATURE_FIND_SIZE(   PARM_size      ,)
     706    IF_FEATURE_FIND_CONTEXT(PARM_context   ,)
     707    IF_FEATURE_FIND_LINKS(  PARM_links     ,)
    473708    };
    474709
     
    476711                             "-a\0"
    477712                             "-o\0"
    478     USE_FEATURE_FIND_NOT(    "!\0"       )
     713    IF_FEATURE_FIND_NOT(    "!\0"       )
    479714#if ENABLE_DESKTOP
    480715                             "-and\0"
    481716                             "-or\0"
    482     USE_FEATURE_FIND_NOT(    "-not\0"    )
     717    IF_FEATURE_FIND_NOT(     "-not\0"    )
    483718#endif
    484719                             "-print\0"
    485     USE_FEATURE_FIND_PRINT0( "-print0\0" )
    486     USE_FEATURE_FIND_DEPTH(  "-depth\0"  )
    487     USE_FEATURE_FIND_PRUNE(  "-prune\0"  )
    488     USE_FEATURE_FIND_DELETE( "-delete\0" )
    489     USE_FEATURE_FIND_EXEC(   "-exec\0"   )
    490     USE_FEATURE_FIND_PAREN(  "(\0"       )
     720    IF_FEATURE_FIND_PRINT0( "-print0\0" )
     721    IF_FEATURE_FIND_DEPTH(  "-depth\0"  )
     722    IF_FEATURE_FIND_PRUNE(  "-prune\0"  )
     723    IF_FEATURE_FIND_DELETE( "-delete\0" )
     724    IF_FEATURE_FIND_EXEC(   "-exec\0"   )
     725    IF_FEATURE_FIND_PAREN(  "(\0"       )
    491726    /* All options starting from here require argument */
    492727                             "-name\0"
    493     USE_FEATURE_FIND_PATH(   "-path\0"   )
    494     USE_FEATURE_FIND_REGEX(  "-regex\0"  )
    495     USE_FEATURE_FIND_TYPE(   "-type\0"   )
    496     USE_FEATURE_FIND_PERM(   "-perm\0"   )
    497     USE_FEATURE_FIND_MTIME(  "-mtime\0"  )
    498     USE_FEATURE_FIND_MMIN(   "-mmin\0"   )
    499     USE_FEATURE_FIND_NEWER(  "-newer\0"  )
    500     USE_FEATURE_FIND_INUM(   "-inum\0"   )
    501     USE_FEATURE_FIND_USER(   "-user\0"   )
    502     USE_FEATURE_FIND_GROUP(  "-group\0"  )
    503     USE_FEATURE_FIND_SIZE(   "-size\0"   )
    504     USE_FEATURE_FIND_CONTEXT("-context\0")
     728                             "-iname\0"
     729    IF_FEATURE_FIND_PATH(   "-path\0"   )
     730    IF_FEATURE_FIND_REGEX(  "-regex\0"  )
     731    IF_FEATURE_FIND_TYPE(   "-type\0"   )
     732    IF_FEATURE_FIND_PERM(   "-perm\0"   )
     733    IF_FEATURE_FIND_MTIME(  "-mtime\0"  )
     734    IF_FEATURE_FIND_MMIN(   "-mmin\0"   )
     735    IF_FEATURE_FIND_NEWER(  "-newer\0"  )
     736    IF_FEATURE_FIND_INUM(   "-inum\0"   )
     737    IF_FEATURE_FIND_USER(   "-user\0"   )
     738    IF_FEATURE_FIND_GROUP(  "-group\0"  )
     739    IF_FEATURE_FIND_SIZE(   "-size\0"   )
     740    IF_FEATURE_FIND_CONTEXT("-context\0")
     741    IF_FEATURE_FIND_LINKS(  "-links\0"  )
    505742                             ;
    506743
     
    508745    unsigned cur_group = 0;
    509746    unsigned cur_action = 0;
    510     USE_FEATURE_FIND_NOT( bool invert_flag = 0; )
    511 
    512     /* 'static' doesn't work here! (gcc 4.1.2) */
     747    IF_FEATURE_FIND_NOT( bool invert_flag = 0; )
     748
     749    /* This is the only place in busybox where we use nested function.
     750     * So far more standard alternatives were bigger. */
     751    /* Auto decl suppresses "func without a prototype" warning: */
     752    auto action* alloc_action(int sizeof_struct, action_fp f);
    513753    action* alloc_action(int sizeof_struct, action_fp f)
    514754    {
    515755        action *ap;
    516756        appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(*appp));
    517         appp[cur_group][cur_action++] = ap = xmalloc(sizeof_struct);
     757        appp[cur_group][cur_action++] = ap = xzalloc(sizeof_struct);
    518758        appp[cur_group][cur_action] = NULL;
    519759        ap->f = f;
    520         USE_FEATURE_FIND_NOT( ap->invert = invert_flag; )
    521         USE_FEATURE_FIND_NOT( invert_flag = 0; )
     760        IF_FEATURE_FIND_NOT( ap->invert = invert_flag; )
     761        IF_FEATURE_FIND_NOT( invert_flag = 0; )
    522762        return ap;
    523763    }
     
    557797
    558798    /* --- Operators --- */
    559         if (parm == PARM_a USE_DESKTOP(|| parm == PARM_and)) {
     799        if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) {
    560800            /* no further special handling required */
    561801        }
    562         else if (parm == PARM_o USE_DESKTOP(|| parm == PARM_or)) {
     802        else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) {
    563803            /* start new OR group */
    564804            cur_group++;
     
    569809        }
    570810#if ENABLE_FEATURE_FIND_NOT
    571         else if (parm == PARM_char_not USE_DESKTOP(|| parm == PARM_not)) {
     811        else if (parm == PARM_char_not IF_DESKTOP(|| parm == PARM_not)) {
    572812            /* also handles "find ! ! -name 'foo*'" */
    573813            invert_flag ^= 1;
     
    577817    /* --- Tests and actions --- */
    578818        else if (parm == PARM_print) {
    579             need_print = 0;
     819            G.need_print = 0;
    580820            /* GNU find ignores '!' here: "find ! -print" */
    581             USE_FEATURE_FIND_NOT( invert_flag = 0; )
     821            IF_FEATURE_FIND_NOT( invert_flag = 0; )
    582822            (void) ALLOC_ACTION(print);
    583823        }
    584824#if ENABLE_FEATURE_FIND_PRINT0
    585825        else if (parm == PARM_print0) {
    586             need_print = 0;
    587             USE_FEATURE_FIND_NOT( invert_flag = 0; )
     826            G.need_print = 0;
     827            IF_FEATURE_FIND_NOT( invert_flag = 0; )
    588828            (void) ALLOC_ACTION(print0);
    589829        }
     
    591831#if ENABLE_FEATURE_FIND_DEPTH
    592832        else if (parm == PARM_depth) {
    593             recurse_flags |= ACTION_DEPTHFIRST;
     833            G.recurse_flags |= ACTION_DEPTHFIRST;
    594834        }
    595835#endif
    596836#if ENABLE_FEATURE_FIND_PRUNE
    597837        else if (parm == PARM_prune) {
    598             USE_FEATURE_FIND_NOT( invert_flag = 0; )
     838            IF_FEATURE_FIND_NOT( invert_flag = 0; )
    599839            (void) ALLOC_ACTION(prune);
    600840        }
     
    602842#if ENABLE_FEATURE_FIND_DELETE
    603843        else if (parm == PARM_delete) {
    604             need_print = 0;
    605             recurse_flags |= ACTION_DEPTHFIRST;
     844            G.need_print = 0;
     845            G.recurse_flags |= ACTION_DEPTHFIRST;
    606846            (void) ALLOC_ACTION(delete);
    607847        }
     
    611851            int i;
    612852            action_exec *ap;
    613             need_print = 0;
    614             USE_FEATURE_FIND_NOT( invert_flag = 0; )
     853            G.need_print = 0;
     854            IF_FEATURE_FIND_NOT( invert_flag = 0; )
    615855            ap = ALLOC_ACTION(exec);
    616856            ap->exec_argv = ++argv; /* first arg after -exec */
    617             ap->exec_argc = 0;
     857            /*ap->exec_argc = 0; - ALLOC_ACTION did it */
    618858            while (1) {
    619                 if (!*argv) /* did not see ';' until end */
    620                     bb_error_msg_and_die("-exec CMD must end by ';'");
    621                 if (LONE_CHAR(argv[0], ';'))
     859                if (!*argv) /* did not see ';' or '+' until end */
     860                    bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
     861                // find -exec echo Foo ">{}<" ";"
     862                // executes "echo Foo <filename>",
     863                // find -exec echo Foo ">{}<" "+"
     864                // executes "echo Foo <filename1> <filename2> <filename3>...".
     865                // TODO (so far we treat "+" just like ";")
     866                if ((argv[0][0] == ';' || argv[0][0] == '+')
     867                 && argv[0][1] == '\0'
     868                ) {
    622869                    break;
     870                }
    623871                argv++;
    624872                ap->exec_argc++;
     
    655903        }
    656904#endif
    657         else if (parm == PARM_name) {
     905        else if (parm == PARM_name || parm == PARM_iname) {
    658906            action_name *ap;
    659907            ap = ALLOC_ACTION(name);
    660908            ap->pattern = arg1;
     909            ap->iname = (parm == PARM_iname);
    661910        }
    662911#if ENABLE_FEATURE_FIND_PATH
     
    692941            ap->perm_char = arg1[0];
    693942            arg1 = plus_minus_num(arg1);
    694             ap->perm_mask = 0;
     943            /*ap->perm_mask = 0; - ALLOC_ACTION did it */
    695944            if (!bb_parse_mode(arg1, &ap->perm_mask))
    696                 bb_error_msg_and_die("invalid mode: %s", arg1);
     945                bb_error_msg_and_die("invalid mode '%s'", arg1);
    697946        }
    698947#endif
     
    7661015                { "b", 512 },
    7671016                { "k", 1024 },
    768                 { }
     1017                { "", 0 }
    7691018            };
    7701019            action_size *ap;
     
    7781027            action_context *ap;
    7791028            ap = ALLOC_ACTION(context);
    780             ap->context = NULL;
     1029            /*ap->context = NULL; - ALLOC_ACTION did it */
    7811030            /* SELinux headers erroneously declare non-const parameter */
    7821031            if (selinux_raw_to_trans_context((char*)arg1, &ap->context))
    783                 bb_perror_msg("%s", arg1);
     1032                bb_simple_perror_msg(arg1);
     1033        }
     1034#endif
     1035#if ENABLE_FEATURE_FIND_LINKS
     1036        else if (parm == PARM_links) {
     1037            action_links *ap;
     1038            ap = ALLOC_ACTION(links);
     1039            ap->links_char = arg1[0];
     1040            ap->links_count = xatoul(plus_minus_num(arg1));
    7841041        }
    7851042#endif
     
    7941051}
    7951052
    796 
    797 int find_main(int argc, char **argv);
    798 int find_main(int argc, char **argv)
     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
     1140int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1141int find_main(int argc UNUSED_PARAM, char **argv)
    7991142{
    8001143    static const char options[] ALIGN1 =
    8011144                      "-follow\0"
    802 USE_FEATURE_FIND_XDEV(    "-xdev\0"    )
    803 USE_FEATURE_FIND_MAXDEPTH("-maxdepth\0")
     1145IF_FEATURE_FIND_XDEV(    "-xdev\0"    )
     1146IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0")
    8041147                      ;
    8051148    enum {
    8061149                      OPT_FOLLOW,
    807 USE_FEATURE_FIND_XDEV(    OPT_XDEV    ,)
    808 USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,)
     1150IF_FEATURE_FIND_XDEV(    OPT_XDEV    ,)
     1151IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
    8091152    };
    8101153
     
    8131156    int i, firstopt, status = EXIT_SUCCESS;
    8141157#if ENABLE_FEATURE_FIND_MAXDEPTH
    815     int maxdepth = INT_MAX;
    816 #endif
    817 
    818     for (firstopt = 1; firstopt < argc; firstopt++) {
     1158    int minmaxdepth[2] = { 0, INT_MAX };
     1159#else
     1160#define minmaxdepth NULL
     1161#endif
     1162
     1163    INIT_G();
     1164
     1165    for (firstopt = 1; argv[firstopt]; firstopt++) {
    8191166        if (argv[firstopt][0] == '-')
    8201167            break;
     
    8431190        int opt = index_in_strings(options, arg);
    8441191        if (opt == OPT_FOLLOW) {
    845             recurse_flags |= ACTION_FOLLOWLINKS;
     1192            G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
    8461193            argp[0] = (char*)"-a";
    8471194        }
     
    8491196        if (opt == OPT_XDEV) {
    8501197            struct stat stbuf;
    851             if (!xdev_count) {
    852                 xdev_count = firstopt - 1;
    853                 xdev_dev = xmalloc(xdev_count * sizeof(dev_t));
     1198            if (!G.xdev_count) {
     1199                G.xdev_count = firstopt - 1;
     1200                G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0]));
    8541201                for (i = 1; i < firstopt; i++) {
    8551202                    /* not xstat(): shouldn't bomb out on
    8561203                     * "find not_exist exist -xdev" */
    857                     if (stat(argv[i], &stbuf))
    858                         stbuf.st_dev = -1L;
    859                     xdev_dev[i-1] = stbuf.st_dev;
     1204                    if (stat(argv[i], &stbuf) == 0)
     1205                        G.xdev_dev[i-1] = stbuf.st_dev;
     1206                    /* else G.xdev_dev[i-1] stays 0 and
     1207                     * won't match any real device dev_t */
    8601208                }
    8611209            }
     
    8641212#endif
    8651213#if ENABLE_FEATURE_FIND_MAXDEPTH
    866         if (opt == OPT_MAXDEPTH) {
     1214        if (opt == OPT_MINDEPTH || opt == OPT_MINDEPTH + 1) {
    8671215            if (!argp[1])
    8681216                bb_show_usage();
    869             maxdepth = xatoi_u(argp[1]);
     1217            minmaxdepth[opt - OPT_MINDEPTH] = xatoi_positive(argp[1]);
    8701218            argp[0] = (char*)"-a";
    8711219            argp[1] = (char*)"-a";
     
    8761224    }
    8771225
    878     actions = parse_params(&argv[firstopt]);
     1226    G.actions = parse_params(&argv[firstopt]);
    8791227
    8801228    for (i = 1; i < firstopt; i++) {
    8811229        if (!recursive_action(argv[i],
    882                 recurse_flags,  /* flags */
     1230                G.recurse_flags,/* flags */
    8831231                fileAction,     /* file action */
    8841232                fileAction,     /* dir action */
    8851233#if ENABLE_FEATURE_FIND_MAXDEPTH
    886                 /* double cast suppresses
    887                  * "cast to ptr from int of different size" */
    888                 (void*)(ptrdiff_t)maxdepth,/* user data */
     1234                minmaxdepth,    /* user data */
    8891235#else
    8901236                NULL,           /* user data */
Note: See TracChangeset for help on using the changeset viewer.