Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (17 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

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

    r821 r1765  
    88 *  Matt Kraai <kraai@alumni.carnegiemellon.edu>.
    99 *
    10  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     10 * Licensed under the GPL version 2, see the file LICENSE in this tarball.
    1111 */
    1212
    13 #include "busybox.h"
    14 #include <stdio.h>
    15 #include <unistd.h>
    16 #include <dirent.h>
    17 #include <string.h>
    18 #include <stdlib.h>
     13/* findutils-4.1.20:
     14 *
     15 * # find file.txt -exec 'echo {}' '{}  {}' ';'
     16 * find: echo file.txt: No such file or directory
     17 * # find file.txt -exec 'echo' '{}  {}' '; '
     18 * find: missing argument to `-exec'
     19 * # find file.txt -exec 'echo {}' '{}  {}' ';' junk
     20 * find: paths must precede expression
     21 * # find file.txt -exec 'echo {}' '{}  {}' ';' junk ';'
     22 * find: paths must precede expression
     23 * # find file.txt -exec 'echo' '{}  {}' ';'
     24 * file.txt  file.txt
     25 * (strace: execve("/bin/echo", ["echo", "file.txt  file.txt"], [ 30 vars ]))
     26 * # find file.txt -exec 'echo' '{}  {}' ';' -print -exec pwd ';'
     27 * file.txt  file.txt
     28 * file.txt
     29 * /tmp
     30 * # find -name '*.c' -o -name '*.h'
     31 * [shows files, *.c and *.h intermixed]
     32 * # find file.txt -name '*f*' -o -name '*t*'
     33 * file.txt
     34 * # find file.txt -name '*z*' -o -name '*t*'
     35 * file.txt
     36 * # find file.txt -name '*f*' -o -name '*z*'
     37 * file.txt
     38 *
     39 * # find t z -name '*t*' -print -o -name '*z*'
     40 * t
     41 * # find t z t z -name '*t*' -o -name '*z*' -print
     42 * z
     43 * z
     44 * # find t z t z '(' -name '*t*' -o -name '*z*' ')' -o -print
     45 * (no output)
     46 */
     47
     48/* Testing script
     49 * ./busybox find "$@" | tee /tmp/bb_find
     50 * echo ==================
     51 * /path/to/gnu/find "$@" | tee /tmp/std_find
     52 * echo ==================
     53 * diff -u /tmp/std_find /tmp/bb_find && echo Identical
     54 */
     55
    1956#include <fnmatch.h>
    20 #include <time.h>
    21 #include <ctype.h>
    22 
    23 static char *pattern;
    24 #ifdef CONFIG_FEATURE_FIND_PRINT0
    25 static char printsep = '\n';
    26 #endif
    27 
    28 #ifdef CONFIG_FEATURE_FIND_TYPE
    29 static int type_mask = 0;
    30 #endif
    31 
    32 #ifdef CONFIG_FEATURE_FIND_PERM
    33 static char perm_char = 0;
    34 static int perm_mask = 0;
    35 #endif
    36 
    37 #ifdef CONFIG_FEATURE_FIND_MTIME
    38 static char mtime_char;
    39 static int mtime_days;
    40 #endif
    41 
    42 #ifdef CONFIG_FEATURE_FIND_MMIN
    43 static char mmin_char;
    44 static int mmin_mins;
    45 #endif
    46 
    47 #ifdef CONFIG_FEATURE_FIND_XDEV
    48 static dev_t *xdev_dev;
    49 static int xdev_count = 0;
    50 #endif
    51 
    52 #ifdef CONFIG_FEATURE_FIND_NEWER
    53 static time_t newer_mtime;
    54 #endif
    55 
    56 #ifdef CONFIG_FEATURE_FIND_INUM
    57 static ino_t inode_num;
    58 #endif
    59 
    60 #ifdef CONFIG_FEATURE_FIND_EXEC
    61 static char **exec_str;
    62 static int num_matches;
    63 static int exec_opt;
    64 #endif
    65 
    66 static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
    67 {
    68 #ifdef CONFIG_FEATURE_FIND_XDEV
     57#include "libbb.h"
     58#if ENABLE_FEATURE_FIND_REGEX
     59#include "xregex.h"
     60#endif
     61
     62/* This is a NOEXEC applet. Be very careful! */
     63
     64
     65USE_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
     66USE_FEATURE_FIND_XDEV(static int xdev_count;)
     67
     68typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *);
     69
     70typedef struct {
     71    action_fp f;
     72#if ENABLE_FEATURE_FIND_NOT
     73    bool invert;
     74#endif
     75} 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;)
     80USE_FEATURE_FIND_PATH(   ACTS(path,  const char *pattern;))
     81USE_FEATURE_FIND_REGEX(  ACTS(regex, regex_t compiled_pattern;))
     82USE_FEATURE_FIND_PRINT0( ACTS(print0))
     83USE_FEATURE_FIND_TYPE(   ACTS(type,  int type_mask;))
     84USE_FEATURE_FIND_PERM(   ACTS(perm,  char perm_char; mode_t perm_mask;))
     85USE_FEATURE_FIND_MTIME(  ACTS(mtime, char mtime_char; unsigned mtime_days;))
     86USE_FEATURE_FIND_MMIN(   ACTS(mmin,  char mmin_char; unsigned mmin_mins;))
     87USE_FEATURE_FIND_NEWER(  ACTS(newer, time_t newer_mtime;))
     88USE_FEATURE_FIND_INUM(   ACTS(inum,  ino_t inode_num;))
     89USE_FEATURE_FIND_USER(   ACTS(user,  uid_t uid;))
     90USE_FEATURE_FIND_SIZE(   ACTS(size,  char size_char; off_t size;))
     91USE_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;))
     92USE_FEATURE_FIND_PAREN(  ACTS(paren, action ***subexpr;))
     93USE_FEATURE_FIND_PRUNE(  ACTS(prune))
     94USE_FEATURE_FIND_DELETE( ACTS(delete))
     95USE_FEATURE_FIND_EXEC(   ACTS(exec,  char **exec_argv; unsigned *subst_count; int exec_argc;))
     96USE_FEATURE_FIND_GROUP(  ACTS(group, gid_t gid;))
     97
     98static action ***actions;
     99static bool need_print = 1;
     100static int recurse_flags = ACTION_RECURSE;
     101
     102#if ENABLE_FEATURE_FIND_EXEC
     103static unsigned count_subst(const char *str)
     104{
     105    unsigned count = 0;
     106    while ((str = strstr(str, "{}")) != NULL) {
     107        count++;
     108        str++;
     109    }
     110    return count;
     111}
     112
     113
     114static char* subst(const char *src, unsigned count, const char* filename)
     115{
     116    char *buf, *dst, *end;
     117    size_t flen = strlen(filename);
     118    /* we replace each '{}' with filename: growth by strlen-2 */
     119    buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1);
     120    while ((end = strstr(src, "{}"))) {
     121        memcpy(dst, src, end - src);
     122        dst += end - src;
     123        src = end + 2;
     124        memcpy(dst, filename, flen);
     125        dst += flen;
     126    }
     127    strcpy(dst, src);
     128    return buf;
     129}
     130#endif
     131
     132/* Return values of ACTFs ('action functions') are a bit mask:
     133 * bit 1=1: prune (use SKIP constant for setting it)
     134 * bit 0=1: matched successfully (TRUE)
     135 */
     136
     137static int exec_actions(action ***appp, const char *fileName, struct stat *statbuf)
     138{
     139    int cur_group;
     140    int cur_action;
     141    int rc = 0;
     142    action **app, *ap;
     143
     144    /* "action group" is a set of actions ANDed together.
     145     * groups are ORed together.
     146     * We simply evaluate each group until we find one in which all actions
     147     * succeed. */
     148
     149    /* -prune is special: if it is encountered, then we won't
     150     * descend into current directory. It doesn't matter whether
     151     * action group (in which -prune sits) will succeed or not:
     152     * find * -prune -name 'f*' -o -name 'm*' -- prunes every dir
     153     * find * -name 'f*' -o -prune -name 'm*' -- prunes all dirs
     154     *     not starting with 'f' */
     155
     156    /* We invert TRUE bit (bit 0). Now 1 there means 'failure'.
     157     * and bitwise OR in "rc |= TRUE ^ ap->f()" will:
     158     * (1) make SKIP (-prune) bit stick; and (2) detect 'failure'.
     159     * On return, bit is restored.  */
     160
     161    cur_group = -1;
     162    while ((app = appp[++cur_group])) {
     163        rc &= ~TRUE; /* 'success' so far, clear TRUE bit */
     164        cur_action = -1;
     165        while (1) {
     166            ap = app[++cur_action];
     167            if (!ap) /* all actions in group were successful */
     168                return rc ^ TRUE; /* restore TRUE bit */
     169            rc |= TRUE ^ ap->f(fileName, statbuf, ap);
     170#if ENABLE_FEATURE_FIND_NOT
     171            if (ap->invert) rc ^= TRUE;
     172#endif
     173            if (rc & TRUE) /* current group failed, try next */
     174                break;
     175        }
     176    }
     177    return rc ^ TRUE; /* restore TRUE bit */
     178}
     179
     180
     181ACTF(name)
     182{
     183    const char *tmp = bb_basename(fileName);
     184    if (tmp != fileName && !*tmp) { /* "foo/bar/". Oh no... go back to 'b' */
     185        tmp--;
     186        while (tmp != fileName && *--tmp != '/')
     187            continue;
     188        if (*tmp == '/')
     189            tmp++;
     190    }
     191    return fnmatch(ap->pattern, tmp, FNM_PERIOD) == 0;
     192}
     193#if ENABLE_FEATURE_FIND_PATH
     194ACTF(path)
     195{
     196    return fnmatch(ap->pattern, fileName, 0) == 0;
     197}
     198#endif
     199#if ENABLE_FEATURE_FIND_REGEX
     200ACTF(regex)
     201{
     202    regmatch_t match;
     203    if (regexec(&ap->compiled_pattern, fileName, 1, &match, 0 /*eflags*/))
     204        return 0; /* no match */
     205    if (match.rm_so)
     206        return 0; /* match doesn't start at pos 0 */
     207    if (fileName[match.rm_eo])
     208        return 0; /* match doesn't end exactly at end of pathname */
     209    return 1;
     210}
     211#endif
     212#if ENABLE_FEATURE_FIND_TYPE
     213ACTF(type)
     214{
     215    return ((statbuf->st_mode & S_IFMT) == ap->type_mask);
     216}
     217#endif
     218#if ENABLE_FEATURE_FIND_PERM
     219ACTF(perm)
     220{
     221    /* -perm +mode: at least one of perm_mask bits are set */
     222    if (ap->perm_char == '+')
     223        return (statbuf->st_mode & ap->perm_mask) != 0;
     224    /* -perm -mode: all of perm_mask are set */
     225    if (ap->perm_char == '-')
     226        return (statbuf->st_mode & ap->perm_mask) == ap->perm_mask;
     227    /* -perm mode: file mode must match perm_mask */
     228    return (statbuf->st_mode & 07777) == ap->perm_mask;
     229}
     230#endif
     231#if ENABLE_FEATURE_FIND_MTIME
     232ACTF(mtime)
     233{
     234    time_t file_age = time(NULL) - statbuf->st_mtime;
     235    time_t mtime_secs = ap->mtime_days * 24*60*60;
     236    if (ap->mtime_char == '+')
     237        return file_age >= mtime_secs + 24*60*60;
     238    if (ap->mtime_char == '-')
     239        return file_age < mtime_secs;
     240    /* just numeric mtime */
     241    return file_age >= mtime_secs && file_age < (mtime_secs + 24*60*60);
     242}
     243#endif
     244#if ENABLE_FEATURE_FIND_MMIN
     245ACTF(mmin)
     246{
     247    time_t file_age = time(NULL) - statbuf->st_mtime;
     248    time_t mmin_secs = ap->mmin_mins * 60;
     249    if (ap->mmin_char == '+')
     250        return file_age >= mmin_secs + 60;
     251    if (ap->mmin_char == '-')
     252        return file_age < mmin_secs;
     253    /* just numeric mmin */
     254    return file_age >= mmin_secs && file_age < (mmin_secs + 60);
     255}
     256#endif
     257#if ENABLE_FEATURE_FIND_NEWER
     258ACTF(newer)
     259{
     260    return (ap->newer_mtime < statbuf->st_mtime);
     261}
     262#endif
     263#if ENABLE_FEATURE_FIND_INUM
     264ACTF(inum)
     265{
     266    return (statbuf->st_ino == ap->inode_num);
     267}
     268#endif
     269#if ENABLE_FEATURE_FIND_EXEC
     270ACTF(exec)
     271{
     272    int i, rc;
     273    char *argv[ap->exec_argc + 1];
     274    for (i = 0; i < ap->exec_argc; i++)
     275        argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName);
     276    argv[i] = NULL; /* terminate the list */
     277
     278    rc = spawn_and_wait(argv);
     279    if (rc < 0)
     280        bb_perror_msg("%s", argv[0]);
     281
     282    i = 0;
     283    while (argv[i])
     284        free(argv[i++]);
     285    return rc == 0; /* return 1 if exitcode 0 */
     286}
     287#endif
     288#if ENABLE_FEATURE_FIND_USER
     289ACTF(user)
     290{
     291    return (statbuf->st_uid == ap->uid);
     292}
     293#endif
     294#if ENABLE_FEATURE_FIND_GROUP
     295ACTF(group)
     296{
     297    return (statbuf->st_gid == ap->gid);
     298}
     299#endif
     300#if ENABLE_FEATURE_FIND_PRINT0
     301ACTF(print0)
     302{
     303    printf("%s%c", fileName, '\0');
     304    return TRUE;
     305}
     306#endif
     307ACTF(print)
     308{
     309    puts(fileName);
     310    return TRUE;
     311}
     312#if ENABLE_FEATURE_FIND_PAREN
     313ACTF(paren)
     314{
     315    return exec_actions(ap->subexpr, fileName, statbuf);
     316}
     317#endif
     318#if ENABLE_FEATURE_FIND_SIZE
     319ACTF(size)
     320{
     321    if (ap->size_char == '+')
     322        return statbuf->st_size > ap->size;
     323    if (ap->size_char == '-')
     324        return statbuf->st_size < ap->size;
     325    return statbuf->st_size == ap->size;
     326}
     327#endif
     328#if ENABLE_FEATURE_FIND_PRUNE
     329/*
     330 * -prune: if -depth is not given, return true and do not descend
     331 * current dir; if -depth is given, return false with no effect.
     332 * Example:
     333 * find dir -name 'asm-*' -prune -o -name '*.[chS]' -print
     334 */
     335ACTF(prune)
     336{
     337    return SKIP + TRUE;
     338}
     339#endif
     340#if ENABLE_FEATURE_FIND_DELETE
     341ACTF(delete)
     342{
     343    int rc;
     344    if (S_ISDIR(statbuf->st_mode)) {
     345        rc = rmdir(fileName);
     346    } else {
     347        rc = unlink(fileName);
     348    }
     349    if (rc < 0)
     350        bb_perror_msg("%s", fileName);
     351    return TRUE;
     352}
     353#endif
     354#if ENABLE_FEATURE_FIND_CONTEXT
     355ACTF(context)
     356{
     357    security_context_t con;
     358    int rc;
     359
     360    if (recurse_flags & ACTION_FOLLOWLINKS) {
     361        rc = getfilecon(fileName, &con);
     362    } else {
     363        rc = lgetfilecon(fileName, &con);
     364    }
     365    if (rc < 0)
     366        return FALSE;
     367    rc = strcmp(ap->context, con);
     368    freecon(con);
     369    return rc == 0;
     370}
     371#endif
     372
     373
     374static int fileAction(const char *fileName, struct stat *statbuf, void *userData, int depth)
     375{
     376    int i;
     377#if ENABLE_FEATURE_FIND_MAXDEPTH
     378    int maxdepth = (int)(ptrdiff_t)userData;
     379
     380    if (depth > maxdepth) return SKIP;
     381#endif
     382
     383#if ENABLE_FEATURE_FIND_XDEV
    69384    if (S_ISDIR(statbuf->st_mode) && xdev_count) {
    70         int i;
    71         for (i=0; i<xdev_count; i++) {
    72             if (xdev_dev[i] != statbuf->st_dev)
    73                 return SKIP;
    74         }
    75     }
    76 #endif
    77     if (pattern != NULL) {
    78         const char *tmp = strrchr(fileName, '/');
    79 
    80         if (tmp == NULL)
    81             tmp = fileName;
    82         else
    83             tmp++;
    84         if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0))
    85             goto no_match;
    86     }
    87 #ifdef CONFIG_FEATURE_FIND_TYPE
    88     if (type_mask != 0) {
    89         if (!((statbuf->st_mode & S_IFMT) == type_mask))
    90             goto no_match;
    91     }
    92 #endif
    93 #ifdef CONFIG_FEATURE_FIND_PERM
    94     if (perm_mask != 0) {
    95         if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) ||
    96              (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) ||
    97              (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0)))
    98             goto no_match;
    99     }
    100 #endif
    101 #ifdef CONFIG_FEATURE_FIND_MTIME
    102     if (mtime_char != 0) {
    103         time_t file_age = time(NULL) - statbuf->st_mtime;
    104         time_t mtime_secs = mtime_days * 24 * 60 * 60;
    105         if (!((isdigit(mtime_char) && file_age >= mtime_secs &&
    106                         file_age < mtime_secs + 24 * 60 * 60) ||
    107                 (mtime_char == '+' && file_age >= mtime_secs + 24 * 60 * 60) ||
    108                 (mtime_char == '-' && file_age < mtime_secs)))
    109             goto no_match;
    110     }
    111 #endif
    112 #ifdef CONFIG_FEATURE_FIND_MMIN
    113     if (mmin_char != 0) {
    114         time_t file_age = time(NULL) - statbuf->st_mtime;
    115         time_t mmin_secs = mmin_mins * 60;
    116         if (!((isdigit(mmin_char) && file_age >= mmin_secs &&
    117                         file_age < mmin_secs + 60) ||
    118                 (mmin_char == '+' && file_age >= mmin_secs + 60) ||
    119                 (mmin_char == '-' && file_age < mmin_secs)))
    120             goto no_match;
    121     }
    122 #endif
    123 #ifdef CONFIG_FEATURE_FIND_NEWER
    124     if (newer_mtime != 0) {
    125         time_t file_age = newer_mtime - statbuf->st_mtime;
    126         if (file_age >= 0)
    127             goto no_match;
    128     }
    129 #endif
    130 #ifdef CONFIG_FEATURE_FIND_INUM
    131     if (inode_num != 0) {
    132         if (!(statbuf->st_ino == inode_num))
    133             goto no_match;
    134     }
    135 #endif
    136 #ifdef CONFIG_FEATURE_FIND_EXEC
    137     if (exec_opt) {
    138         int i;
    139         char *cmd_string = "";
    140         for (i = 0; i < num_matches; i++)
    141             cmd_string = bb_xasprintf("%s%s%s", cmd_string, exec_str[i], fileName);
    142         cmd_string = bb_xasprintf("%s%s", cmd_string, exec_str[num_matches]);
    143         system(cmd_string);
    144         goto no_match;
    145     }
    146 #endif
    147 
    148 #ifdef CONFIG_FEATURE_FIND_PRINT0
    149     printf("%s%c", fileName, printsep);
     385        for (i = 0; i < xdev_count; i++) {
     386            if (xdev_dev[i] == statbuf->st_dev)
     387                break;
     388        }
     389        if (i == xdev_count)
     390            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);
     397    /* Cannot return 0: our caller, recursive_action(),
     398     * will perror() and skip dirs (if called on dir) */
     399    return (i & SKIP) ? SKIP : TRUE;
     400}
     401
     402
     403#if ENABLE_FEATURE_FIND_TYPE
     404static int find_type(const char *type)
     405{
     406    int mask = 0;
     407
     408    if (*type == 'b')
     409        mask = S_IFBLK;
     410    else if (*type == 'c')
     411        mask = S_IFCHR;
     412    else if (*type == 'd')
     413        mask = S_IFDIR;
     414    else if (*type == 'p')
     415        mask = S_IFIFO;
     416    else if (*type == 'f')
     417        mask = S_IFREG;
     418    else if (*type == 'l')
     419        mask = S_IFLNK;
     420    else if (*type == 's')
     421        mask = S_IFSOCK;
     422
     423    if (mask == 0 || *(type + 1) != '\0')
     424        bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
     425
     426    return mask;
     427}
     428#endif
     429
     430#if ENABLE_FEATURE_FIND_PERM \
     431 || ENABLE_FEATURE_FIND_MTIME || ENABLE_FEATURE_FIND_MMIN \
     432 || ENABLE_FEATURE_FIND_SIZE
     433static const char* plus_minus_num(const char* str)
     434{
     435    if (*str == '-' || *str == '+')
     436        str++;
     437    return str;
     438}
     439#endif
     440
     441static action*** parse_params(char **argv)
     442{
     443    enum {
     444                             PARM_a         ,
     445                             PARM_o         ,
     446    USE_FEATURE_FIND_NOT(    PARM_char_not  ,)
     447#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,)
     459    /* 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   ,)
     473    };
     474
     475    static const char params[] ALIGN1 =
     476                             "-a\0"
     477                             "-o\0"
     478    USE_FEATURE_FIND_NOT(    "!\0"       )
     479#if ENABLE_DESKTOP
     480                             "-and\0"
     481                             "-or\0"
     482    USE_FEATURE_FIND_NOT(    "-not\0"    )
     483#endif
     484                             "-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"       )
     491    /* All options starting from here require argument */
     492                             "-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")
     505                             ;
     506
     507    action*** appp;
     508    unsigned cur_group = 0;
     509    unsigned cur_action = 0;
     510    USE_FEATURE_FIND_NOT( bool invert_flag = 0; )
     511
     512    /* 'static' doesn't work here! (gcc 4.1.2) */
     513    action* alloc_action(int sizeof_struct, action_fp f)
     514    {
     515        action *ap;
     516        appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(*appp));
     517        appp[cur_group][cur_action++] = ap = xmalloc(sizeof_struct);
     518        appp[cur_group][cur_action] = NULL;
     519        ap->f = f;
     520        USE_FEATURE_FIND_NOT( ap->invert = invert_flag; )
     521        USE_FEATURE_FIND_NOT( invert_flag = 0; )
     522        return ap;
     523    }
     524
     525#define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name)
     526
     527    appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */
     528
     529/* Actions have side effects and return a true or false value
     530 * We implement: -print, -print0, -exec
     531 *
     532 * The rest are tests.
     533 *
     534 * Tests and actions are grouped by operators
     535 * ( expr )              Force precedence
     536 * ! expr                True if expr is false
     537 * -not expr             Same as ! expr
     538 * expr1 [-a[nd]] expr2  And; expr2 is not evaluated if expr1 is false
     539 * expr1 -o[r] expr2     Or; expr2 is not evaluated if expr1 is true
     540 * expr1 , expr2         List; both expr1 and expr2 are always evaluated
     541 * We implement: (), -a, -o
     542 */
     543    while (*argv) {
     544        const char *arg = argv[0];
     545        int parm = index_in_strings(params, arg);
     546        const char *arg1 = argv[1];
     547
     548        if (parm >= PARM_name) {
     549            /* All options starting from -name require argument */
     550            if (!arg1)
     551                bb_error_msg_and_die(bb_msg_requires_arg, arg);
     552            argv++;
     553        }
     554
     555        /* We can use big switch() here, but on i386
     556         * it doesn't give smaller code. Other arches? */
     557
     558    /* --- Operators --- */
     559        if (parm == PARM_a USE_DESKTOP(|| parm == PARM_and)) {
     560            /* no further special handling required */
     561        }
     562        else if (parm == PARM_o USE_DESKTOP(|| parm == PARM_or)) {
     563            /* start new OR group */
     564            cur_group++;
     565            appp = xrealloc(appp, (cur_group+2) * sizeof(*appp));
     566            /*appp[cur_group] = NULL; - already NULL */
     567            appp[cur_group+1] = NULL;
     568            cur_action = 0;
     569        }
     570#if ENABLE_FEATURE_FIND_NOT
     571        else if (parm == PARM_char_not USE_DESKTOP(|| parm == PARM_not)) {
     572            /* also handles "find ! ! -name 'foo*'" */
     573            invert_flag ^= 1;
     574        }
     575#endif
     576
     577    /* --- Tests and actions --- */
     578        else if (parm == PARM_print) {
     579            need_print = 0;
     580            /* GNU find ignores '!' here: "find ! -print" */
     581            USE_FEATURE_FIND_NOT( invert_flag = 0; )
     582            (void) ALLOC_ACTION(print);
     583        }
     584#if ENABLE_FEATURE_FIND_PRINT0
     585        else if (parm == PARM_print0) {
     586            need_print = 0;
     587            USE_FEATURE_FIND_NOT( invert_flag = 0; )
     588            (void) ALLOC_ACTION(print0);
     589        }
     590#endif
     591#if ENABLE_FEATURE_FIND_DEPTH
     592        else if (parm == PARM_depth) {
     593            recurse_flags |= ACTION_DEPTHFIRST;
     594        }
     595#endif
     596#if ENABLE_FEATURE_FIND_PRUNE
     597        else if (parm == PARM_prune) {
     598            USE_FEATURE_FIND_NOT( invert_flag = 0; )
     599            (void) ALLOC_ACTION(prune);
     600        }
     601#endif
     602#if ENABLE_FEATURE_FIND_DELETE
     603        else if (parm == PARM_delete) {
     604            need_print = 0;
     605            recurse_flags |= ACTION_DEPTHFIRST;
     606            (void) ALLOC_ACTION(delete);
     607        }
     608#endif
     609#if ENABLE_FEATURE_FIND_EXEC
     610        else if (parm == PARM_exec) {
     611            int i;
     612            action_exec *ap;
     613            need_print = 0;
     614            USE_FEATURE_FIND_NOT( invert_flag = 0; )
     615            ap = ALLOC_ACTION(exec);
     616            ap->exec_argv = ++argv; /* first arg after -exec */
     617            ap->exec_argc = 0;
     618            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], ';'))
     622                    break;
     623                argv++;
     624                ap->exec_argc++;
     625            }
     626            if (ap->exec_argc == 0)
     627                bb_error_msg_and_die(bb_msg_requires_arg, arg);
     628            ap->subst_count = xmalloc(ap->exec_argc * sizeof(int));
     629            i = ap->exec_argc;
     630            while (i--)
     631                ap->subst_count[i] = count_subst(ap->exec_argv[i]);
     632        }
     633#endif
     634#if ENABLE_FEATURE_FIND_PAREN
     635        else if (parm == PARM_char_brace) {
     636            action_paren *ap;
     637            char **endarg;
     638            unsigned nested = 1;
     639
     640            endarg = argv;
     641            while (1) {
     642                if (!*++endarg)
     643                    bb_error_msg_and_die("unpaired '('");
     644                if (LONE_CHAR(*endarg, '('))
     645                    nested++;
     646                else if (LONE_CHAR(*endarg, ')') && !--nested) {
     647                    *endarg = NULL;
     648                    break;
     649                }
     650            }
     651            ap = ALLOC_ACTION(paren);
     652            ap->subexpr = parse_params(argv + 1);
     653            *endarg = (char*) ")"; /* restore NULLed parameter */
     654            argv = endarg;
     655        }
     656#endif
     657        else if (parm == PARM_name) {
     658            action_name *ap;
     659            ap = ALLOC_ACTION(name);
     660            ap->pattern = arg1;
     661        }
     662#if ENABLE_FEATURE_FIND_PATH
     663        else if (parm == PARM_path) {
     664            action_path *ap;
     665            ap = ALLOC_ACTION(path);
     666            ap->pattern = arg1;
     667        }
     668#endif
     669#if ENABLE_FEATURE_FIND_REGEX
     670        else if (parm == PARM_regex) {
     671            action_regex *ap;
     672            ap = ALLOC_ACTION(regex);
     673            xregcomp(&ap->compiled_pattern, arg1, 0 /*cflags*/);
     674        }
     675#endif
     676#if ENABLE_FEATURE_FIND_TYPE
     677        else if (parm == PARM_type) {
     678            action_type *ap;
     679            ap = ALLOC_ACTION(type);
     680            ap->type_mask = find_type(arg1);
     681        }
     682#endif
     683#if ENABLE_FEATURE_FIND_PERM
     684/* -perm mode   File's permission bits are exactly mode (octal or symbolic).
     685 *              Symbolic modes use mode 0 as a point of departure.
     686 * -perm -mode  All of the permission bits mode are set for the file.
     687 * -perm +mode  Any of the permission bits mode are set for the file.
     688 */
     689        else if (parm == PARM_perm) {
     690            action_perm *ap;
     691            ap = ALLOC_ACTION(perm);
     692            ap->perm_char = arg1[0];
     693            arg1 = plus_minus_num(arg1);
     694            ap->perm_mask = 0;
     695            if (!bb_parse_mode(arg1, &ap->perm_mask))
     696                bb_error_msg_and_die("invalid mode: %s", arg1);
     697        }
     698#endif
     699#if ENABLE_FEATURE_FIND_MTIME
     700        else if (parm == PARM_mtime) {
     701            action_mtime *ap;
     702            ap = ALLOC_ACTION(mtime);
     703            ap->mtime_char = arg1[0];
     704            ap->mtime_days = xatoul(plus_minus_num(arg1));
     705        }
     706#endif
     707#if ENABLE_FEATURE_FIND_MMIN
     708        else if (parm == PARM_mmin) {
     709            action_mmin *ap;
     710            ap = ALLOC_ACTION(mmin);
     711            ap->mmin_char = arg1[0];
     712            ap->mmin_mins = xatoul(plus_minus_num(arg1));
     713        }
     714#endif
     715#if ENABLE_FEATURE_FIND_NEWER
     716        else if (parm == PARM_newer) {
     717            struct stat stat_newer;
     718            action_newer *ap;
     719            ap = ALLOC_ACTION(newer);
     720            xstat(arg1, &stat_newer);
     721            ap->newer_mtime = stat_newer.st_mtime;
     722        }
     723#endif
     724#if ENABLE_FEATURE_FIND_INUM
     725        else if (parm == PARM_inum) {
     726            action_inum *ap;
     727            ap = ALLOC_ACTION(inum);
     728            ap->inode_num = xatoul(arg1);
     729        }
     730#endif
     731#if ENABLE_FEATURE_FIND_USER
     732        else if (parm == PARM_user) {
     733            action_user *ap;
     734            ap = ALLOC_ACTION(user);
     735            ap->uid = bb_strtou(arg1, NULL, 10);
     736            if (errno)
     737                ap->uid = xuname2uid(arg1);
     738        }
     739#endif
     740#if ENABLE_FEATURE_FIND_GROUP
     741        else if (parm == PARM_group) {
     742            action_group *ap;
     743            ap = ALLOC_ACTION(group);
     744            ap->gid = bb_strtou(arg1, NULL, 10);
     745            if (errno)
     746                ap->gid = xgroup2gid(arg1);
     747        }
     748#endif
     749#if ENABLE_FEATURE_FIND_SIZE
     750        else if (parm == PARM_size) {
     751/* -size n[bckw]: file uses n units of space
     752 * b (default): units are 512-byte blocks
     753 * c: 1 byte
     754 * k: kilobytes
     755 * w: 2-byte words
     756 */
     757#if ENABLE_LFS
     758#define XATOU_SFX xatoull_sfx
    150759#else
    151     puts(fileName);
    152 #endif
    153 no_match:
    154     return (TRUE);
    155 }
    156 
    157 #ifdef CONFIG_FEATURE_FIND_TYPE
    158 static int find_type(char *type)
    159 {
    160     int mask = 0;
    161 
    162     switch (type[0]) {
    163         case 'b':
    164             mask = S_IFBLK;
    165             break;
    166         case 'c':
    167             mask = S_IFCHR;
    168             break;
    169         case 'd':
    170             mask = S_IFDIR;
    171             break;
    172         case 'p':
    173             mask = S_IFIFO;
    174             break;
    175         case 'f':
    176             mask = S_IFREG;
    177             break;
    178         case 'l':
    179             mask = S_IFLNK;
    180             break;
    181         case 's':
    182             mask = S_IFSOCK;
    183             break;
    184     }
    185 
    186     if (mask == 0 || type[1] != '\0')
    187         bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
    188 
    189     return mask;
    190 }
    191 #endif
    192 
     760#define XATOU_SFX xatoul_sfx
     761#endif
     762            static const struct suffix_mult find_suffixes[] = {
     763                { "c", 1 },
     764                { "w", 2 },
     765                { "", 512 },
     766                { "b", 512 },
     767                { "k", 1024 },
     768                { }
     769            };
     770            action_size *ap;
     771            ap = ALLOC_ACTION(size);
     772            ap->size_char = arg1[0];
     773            ap->size = XATOU_SFX(plus_minus_num(arg1), find_suffixes);
     774        }
     775#endif
     776#if ENABLE_FEATURE_FIND_CONTEXT
     777        else if (parm == PARM_context) {
     778            action_context *ap;
     779            ap = ALLOC_ACTION(context);
     780            ap->context = NULL;
     781            /* SELinux headers erroneously declare non-const parameter */
     782            if (selinux_raw_to_trans_context((char*)arg1, &ap->context))
     783                bb_perror_msg("%s", arg1);
     784        }
     785#endif
     786        else {
     787            bb_error_msg("unrecognized: %s", arg);
     788            bb_show_usage();
     789        }
     790        argv++;
     791    }
     792    return appp;
     793#undef ALLOC_ACTION
     794}
     795
     796
     797int find_main(int argc, char **argv);
    193798int find_main(int argc, char **argv)
    194799{
    195     int dereference = FALSE;
     800    static const char options[] ALIGN1 =
     801                      "-follow\0"
     802USE_FEATURE_FIND_XDEV(    "-xdev\0"    )
     803USE_FEATURE_FIND_MAXDEPTH("-maxdepth\0")
     804                      ;
     805    enum {
     806                      OPT_FOLLOW,
     807USE_FEATURE_FIND_XDEV(    OPT_XDEV    ,)
     808USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,)
     809    };
     810
     811    char *arg;
     812    char **argp;
    196813    int i, firstopt, status = EXIT_SUCCESS;
     814#if ENABLE_FEATURE_FIND_MAXDEPTH
     815    int maxdepth = INT_MAX;
     816#endif
    197817
    198818    for (firstopt = 1; firstopt < argc; firstopt++) {
    199819        if (argv[firstopt][0] == '-')
    200820            break;
    201     }
    202 
    203     /* Parse any options */
    204     for (i = firstopt; i < argc; i++) {
    205         if (strcmp(argv[i], "-follow") == 0)
    206             dereference = TRUE;
    207         else if (strcmp(argv[i], "-print") == 0) {
    208             ;
    209             }
    210 #ifdef CONFIG_FEATURE_FIND_PRINT0
    211         else if (strcmp(argv[i], "-print0") == 0)
    212             printsep = '\0';
    213 #endif
    214         else if (strcmp(argv[i], "-name") == 0) {
    215             if (++i == argc)
    216                 bb_error_msg_and_die(bb_msg_requires_arg, "-name");
    217             pattern = argv[i];
    218 #ifdef CONFIG_FEATURE_FIND_TYPE
    219         } else if (strcmp(argv[i], "-type") == 0) {
    220             if (++i == argc)
    221                 bb_error_msg_and_die(bb_msg_requires_arg, "-type");
    222             type_mask = find_type(argv[i]);
    223 #endif
    224 #ifdef CONFIG_FEATURE_FIND_PERM
    225         } else if (strcmp(argv[i], "-perm") == 0) {
    226             char *end;
    227             if (++i == argc)
    228                 bb_error_msg_and_die(bb_msg_requires_arg, "-perm");
    229             perm_mask = strtol(argv[i], &end, 8);
    230             if ((end[0] != '\0') || (perm_mask > 07777))
    231                 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-perm");
    232             if ((perm_char = argv[i][0]) == '-')
    233                 perm_mask = -perm_mask;
    234 #endif
    235 #ifdef CONFIG_FEATURE_FIND_MTIME
    236         } else if (strcmp(argv[i], "-mtime") == 0) {
    237             char *end;
    238             if (++i == argc)
    239                 bb_error_msg_and_die(bb_msg_requires_arg, "-mtime");
    240             mtime_days = strtol(argv[i], &end, 10);
    241             if (end[0] != '\0')
    242                 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-mtime");
    243             if ((mtime_char = argv[i][0]) == '-')
    244                 mtime_days = -mtime_days;
    245 #endif
    246 #ifdef CONFIG_FEATURE_FIND_MMIN
    247         } else if (strcmp(argv[i], "-mmin") == 0) {
    248             char *end;
    249             if (++i == argc)
    250                 bb_error_msg_and_die(bb_msg_requires_arg, "-mmin");
    251             mmin_mins = strtol(argv[i], &end, 10);
    252             if (end[0] != '\0')
    253                 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-mmin");
    254             if ((mmin_char = argv[i][0]) == '-')
    255                 mmin_mins = -mmin_mins;
    256 #endif
    257 #ifdef CONFIG_FEATURE_FIND_XDEV
    258         } else if (strcmp(argv[i], "-xdev") == 0) {
     821        if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!'))
     822            break;
     823#if ENABLE_FEATURE_FIND_PAREN
     824        if (LONE_CHAR(argv[firstopt], '('))
     825            break;
     826#endif
     827    }
     828    if (firstopt == 1) {
     829        argv[0] = (char*)".";
     830        argv--;
     831        firstopt++;
     832    }
     833
     834/* All options always return true. They always take effect
     835 * rather than being processed only when their place in the
     836 * expression is reached.
     837 * We implement: -follow, -xdev, -maxdepth
     838 */
     839    /* Process options, and replace then with -a */
     840    /* (-a will be ignored by recursive parser later) */
     841    argp = &argv[firstopt];
     842    while ((arg = argp[0])) {
     843        int opt = index_in_strings(options, arg);
     844        if (opt == OPT_FOLLOW) {
     845            recurse_flags |= ACTION_FOLLOWLINKS;
     846            argp[0] = (char*)"-a";
     847        }
     848#if ENABLE_FEATURE_FIND_XDEV
     849        if (opt == OPT_XDEV) {
    259850            struct stat stbuf;
    260 
    261             xdev_count = ( firstopt - 1 ) ? ( firstopt - 1 ) : 1;
    262             xdev_dev = xmalloc ( xdev_count * sizeof( dev_t ));
    263 
    264             if ( firstopt == 1 ) {
    265                 xstat ( ".", &stbuf );
    266                 xdev_dev [0] = stbuf. st_dev;
    267             }
    268             else {
    269 
     851            if (!xdev_count) {
     852                xdev_count = firstopt - 1;
     853                xdev_dev = xmalloc(xdev_count * sizeof(dev_t));
    270854                for (i = 1; i < firstopt; i++) {
    271                     xstat ( argv [i], &stbuf );
    272                     xdev_dev [i-1] = stbuf. st_dev;
     855                    /* not xstat(): shouldn't bomb out on
     856                     * "find not_exist exist -xdev" */
     857                    if (stat(argv[i], &stbuf))
     858                        stbuf.st_dev = -1L;
     859                    xdev_dev[i-1] = stbuf.st_dev;
    273860                }
    274861            }
    275 #endif
    276 #ifdef CONFIG_FEATURE_FIND_NEWER
    277         } else if (strcmp(argv[i], "-newer") == 0) {
    278             struct stat stat_newer;
    279             if (++i == argc)
    280                 bb_error_msg_and_die(bb_msg_requires_arg, "-newer");
    281             xstat (argv[i], &stat_newer);
    282             newer_mtime = stat_newer.st_mtime;
    283 #endif
    284 #ifdef CONFIG_FEATURE_FIND_INUM
    285         } else if (strcmp(argv[i], "-inum") == 0) {
    286             char *end;
    287             if (++i == argc)
    288                 bb_error_msg_and_die(bb_msg_requires_arg, "-inum");
    289             inode_num = strtol(argv[i], &end, 10);
    290             if (end[0] != '\0')
    291                 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-inum");
    292 #endif
    293 #ifdef CONFIG_FEATURE_FIND_EXEC
    294         } else if (strcmp(argv[i], "-exec") == 0) {
    295             int b_pos;
    296             char *cmd_string = "";
    297 
    298             while (i++) {
    299                 if (i == argc)
    300                     bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
    301                 if (*argv[i] == ';')
    302                     break;
    303                 cmd_string = bb_xasprintf("%s %s", cmd_string, argv[i]);
    304             }
    305 
    306             if (*cmd_string == 0)
    307                 bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
    308             cmd_string++;
    309             exec_str = xmalloc(sizeof(char *));
    310 
    311             while ((b_pos = strstr(cmd_string, "{}") - cmd_string), (b_pos >= 0)) {
    312                 num_matches++;
    313                 exec_str = xrealloc(exec_str, (num_matches + 1) * sizeof(char *));
    314                 exec_str[num_matches - 1] = bb_xstrndup(cmd_string, b_pos);
    315                 cmd_string += b_pos + 2;
    316             }
    317             exec_str[num_matches] = bb_xstrdup(cmd_string);
    318             exec_opt = 1;
    319 #endif
    320         } else
    321             bb_show_usage();
    322     }
    323 
    324     if (firstopt == 1) {
    325         if (! recursive_action(".", TRUE, dereference, FALSE, fileAction,
    326                     fileAction, NULL))
     862            argp[0] = (char*)"-a";
     863        }
     864#endif
     865#if ENABLE_FEATURE_FIND_MAXDEPTH
     866        if (opt == OPT_MAXDEPTH) {
     867            if (!argp[1])
     868                bb_show_usage();
     869            maxdepth = xatoi_u(argp[1]);
     870            argp[0] = (char*)"-a";
     871            argp[1] = (char*)"-a";
     872            argp++;
     873        }
     874#endif
     875        argp++;
     876    }
     877
     878    actions = parse_params(&argv[firstopt]);
     879
     880    for (i = 1; i < firstopt; i++) {
     881        if (!recursive_action(argv[i],
     882                recurse_flags,  /* flags */
     883                fileAction,     /* file action */
     884                fileAction,     /* dir action */
     885#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 */
     889#else
     890                NULL,           /* user data */
     891#endif
     892                0))             /* depth */
    327893            status = EXIT_FAILURE;
    328     } else {
    329         for (i = 1; i < firstopt; i++) {
    330             if (! recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
    331                         fileAction, NULL))
    332                 status = EXIT_FAILURE;
    333         }
    334     }
    335 
     894    }
    336895    return status;
    337896}
Note: See TracChangeset for help on using the changeset viewer.