Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/findutils


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

Update to busybox 1.7.2

Location:
branches/2.2.5/mindi-busybox/findutils
Files:
1 added
2 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/findutils/Config.in

    r821 r1765  
    66menu "Finding Utilities"
    77
    8 config CONFIG_FIND
     8config FIND
    99    bool "find"
    1010    default n
     
    1212      find is used to search your system to find specified files.
    1313
    14 config CONFIG_FEATURE_FIND_PRINT0
     14config FEATURE_FIND_PRINT0
    1515    bool "Enable -print0 option"
    1616    default y
    17     depends on CONFIG_FIND
     17    depends on FIND
    1818    help
    1919      Causes output names to be separated by a null character
     
    2222      interpreted by other programs.
    2323
    24 config CONFIG_FEATURE_FIND_MTIME
     24config FEATURE_FIND_MTIME
    2525    bool "Enable modified time matching (-mtime) option"
    2626    default y
    27     depends on CONFIG_FIND
     27    depends on FIND
    2828    help
    2929      Allow searching based on the modification time of
    3030      files, in days.
    3131
    32 config CONFIG_FEATURE_FIND_MMIN
    33     bool "Enable modified time matching (-min) option"
    34     default y
    35     depends on CONFIG_FIND
     32config FEATURE_FIND_MMIN
     33    bool "Enable modified time matching (-mmin) option"
     34    default y
     35    depends on FIND
    3636    help
    3737      Allow searching based on the modification time of
    3838      files, in minutes.
    3939
    40 config CONFIG_FEATURE_FIND_PERM
     40config FEATURE_FIND_PERM
    4141    bool "Enable permissions matching (-perm) option"
    4242    default y
    43     depends on CONFIG_FIND
     43    depends on FIND
    4444    help
    4545      Enable searching based on file permissions.
    4646
    47 config CONFIG_FEATURE_FIND_TYPE
     47config FEATURE_FIND_TYPE
    4848    bool "Enable filetype matching (-type) option"
    4949    default y
    50     depends on CONFIG_FIND
     50    depends on FIND
    5151    help
    5252      Enable searching based on file type (file,
    5353      directory, socket, device, etc.).
    5454
    55 config CONFIG_FEATURE_FIND_XDEV
     55config FEATURE_FIND_XDEV
    5656    bool "Enable stay in filesystem (-xdev) option"
    5757    default y
    58     depends on CONFIG_FIND
    59     help
    60       This option will allow find to restrict searches to a single
    61       filesystem.
    62 
    63 config CONFIG_FEATURE_FIND_NEWER
     58    depends on FIND
     59    help
     60      This option allows find to restrict searches to a single filesystem.
     61
     62config FEATURE_FIND_MAXDEPTH
     63    bool "Enable -maxdepth N option"
     64    default y
     65    depends on FIND
     66    help
     67      This option enables -maxdepth N option.
     68
     69config FEATURE_FIND_NEWER
    6470    bool "Enable -newer option for comparing file mtimes"
    6571    default y
    66     depends on CONFIG_FIND
     72    depends on FIND
    6773    help
    6874      Support the 'find -newer' option for finding any files which have
    6975      a modified time that is more recent than the specified FILE.
    7076
    71 config CONFIG_FEATURE_FIND_INUM
     77config FEATURE_FIND_INUM
    7278    bool "Enable inode number matching (-inum) option"
    7379    default y
    74     depends on CONFIG_FIND
     80    depends on FIND
    7581    help
    7682      Support the 'find -inum' option for searching by inode number.
    7783
    78 config CONFIG_FEATURE_FIND_EXEC
     84config FEATURE_FIND_EXEC
    7985    bool "Enable (-exec) option allowing execution of commands"
    8086    default y
    81     depends on CONFIG_FIND
     87    depends on FIND
    8288    help
    8389      Support the 'find -exec' option for executing commands based upon
    8490      the files matched.
    8591
    86 config CONFIG_GREP
     92config FEATURE_FIND_USER
     93    bool "Enable username/uid matching (-user) option"
     94    default y
     95    depends on FIND
     96    help
     97      Support the 'find -user' option for searching by username or uid.
     98
     99config FEATURE_FIND_GROUP
     100    bool "Enable group/gid matching (-group) option"
     101    default y
     102    depends on FIND
     103    help
     104      Support the 'find -group' option for searching by group name or gid.
     105
     106config FEATURE_FIND_NOT
     107    bool "Enable the 'not' (!) operator"
     108    default y
     109    depends on FIND
     110    help
     111      Support the '!' operator to invert the test results.
     112      If 'Enable full-blown desktop' is enabled, then will also support
     113      the non-POSIX notation '-not'.
     114
     115config FEATURE_FIND_DEPTH
     116    bool "Enable the -depth option"
     117    default y
     118    depends on FIND
     119    help
     120      Process each directory's contents before the directory itself.
     121
     122config FEATURE_FIND_PAREN
     123    bool "Enable parens in options"
     124    default y
     125    depends on FIND
     126    help
     127      Enable usage of parens '(' to specify logical order of arguments.
     128
     129config FEATURE_FIND_SIZE
     130    bool "Enable (-size) option allowing matching for file size"
     131    default y
     132    depends on FIND
     133    help
     134      Support the 'find -size' option for searching by file size.
     135
     136config FEATURE_FIND_PRUNE
     137    bool "Enable (-prune) option allowing to exclude subdirectories"
     138    default y
     139    depends on FIND
     140    help
     141      If the file is a directory, dont descend into it. Useful for
     142      exclusion .svn and CVS directories.
     143
     144config FEATURE_FIND_DELETE
     145    bool "Enable -delete option allowing to delete files"
     146    default n
     147    depends on FIND && FEATURE_FIND_DEPTH
     148    help
     149      Support the 'find -delete' option for deleting files and direcotries.
     150      WARNING: This option can do much harm if used wrong. Busybox will not
     151      try to protect the user from doing stupid things. Use with care.
     152
     153config FEATURE_FIND_PATH
     154    bool "Enable -path option allowing to match pathname patterns"
     155    default y
     156    depends on FIND
     157    help
     158      The -path option matches whole pathname instead of just filename.
     159
     160config FEATURE_FIND_REGEX
     161    bool "Enable -regex: match pathname to regex"
     162    default y
     163    depends on FIND
     164    help
     165      The -regex option matches whole pathname against regular expression.
     166
     167config FEATURE_FIND_CONTEXT
     168    bool "Enable (-context) option for matching security context"
     169    default n
     170    depends on FIND && SELINUX
     171    help
     172      Support the 'find -context' option for matching security context.
     173
     174config GREP
    87175    bool "grep"
    88176    default n
     
    90178      grep is used to search files for a specified pattern.
    91179
    92 config CONFIG_FEATURE_GREP_EGREP_ALIAS
     180config FEATURE_GREP_EGREP_ALIAS
    93181    bool "Support extended regular expressions (egrep & grep -E)"
    94182    default y
    95     depends on CONFIG_GREP
     183    depends on GREP
    96184    help
    97185      Enabled support for extended regular expressions.  Extended
     
    99187      and various repetition operators.
    100188
    101 config CONFIG_FEATURE_GREP_FGREP_ALIAS
     189config FEATURE_GREP_FGREP_ALIAS
    102190    bool "Alias fgrep to grep -F"
    103191    default y
    104     depends on CONFIG_GREP
     192    depends on GREP
    105193    help
    106194      fgrep sees the search pattern as a normal string rather than
     
    108196      grep -F is always builtin, this just creates the fgrep alias.
    109197
    110 config CONFIG_FEATURE_GREP_CONTEXT
     198config FEATURE_GREP_CONTEXT
    111199    bool "Enable before and after context flags (-A, -B and -C)"
    112200    default y
    113     depends on CONFIG_GREP
     201    depends on GREP
    114202    help
    115203      Print the specified number of leading (-B) and/or trailing (-A)
     
    117205      Print the specified number of context lines (-C).
    118206
    119 config CONFIG_XARGS
     207config XARGS
    120208    bool "xargs"
    121209    default n
     
    124212      every item from standard input.
    125213
    126 config CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
     214config FEATURE_XARGS_SUPPORT_CONFIRMATION
    127215    bool "Enable prompt and confirmation option -p"
    128216    default n
    129     depends on CONFIG_XARGS
     217    depends on XARGS
    130218    help
    131219      Support prompt the user about whether to run each command
    132220      line and read a line from the terminal.
    133221
    134 config CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
     222config FEATURE_XARGS_SUPPORT_QUOTES
    135223    bool "Enable support single and double quotes and backslash"
    136224    default n
    137     depends on CONFIG_XARGS
     225    depends on XARGS
    138226    help
    139227      Default xargs unsupport single and double quotes
    140228      and backslash for can use aruments with spaces.
    141229
    142 config CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
     230config FEATURE_XARGS_SUPPORT_TERMOPT
    143231    bool "Enable support options -x"
    144232    default n
    145     depends on CONFIG_XARGS
     233    depends on XARGS
    146234    help
    147235      Enable support exit if the size (see the -s or -n option)
    148236      is exceeded.
    149237
    150 config CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
    151     bool "Enable options -0"
    152     default n
    153     depends on CONFIG_XARGS
     238config FEATURE_XARGS_SUPPORT_ZERO_TERM
     239    bool "Enable null terminated option -0"
     240    default n
     241    depends on XARGS
    154242    help
    155243      Enable input filenames are terminated by a null character
  • 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}
  • branches/2.2.5/mindi-busybox/findutils/grep.c

    r821 r1765  
    66 * Copyright (C) 1999,2000,2001 by Mark Whitley <markw@codepoet.org>
    77 *
    8  * Licensed under the GPL v2, see the file LICENSE in this tarball.
     8 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
    99 */
    1010/* BB_AUDIT SUSv3 defects - unsupported option -x.  */
     
    1515 * correction "-e pattern1 -e pattern2" logic and more optimizations.
    1616 * precompiled regex
    17 */
    18 
    19 #include "busybox.h"
    20 #include <stdio.h>
    21 #include <stdlib.h>
    22 #include <getopt.h>
    23 #include <string.h>
    24 #include <errno.h>
     17 */
     18/*
     19 * (C) 2006 Jac Goudsmit added -o option
     20 */
     21
     22#include "libbb.h"
    2523#include "xregex.h"
    2624
    27 
    2825/* options */
    29 static unsigned long opt;
    30 #define GREP_OPTS "lnqvscFiHhe:f:L"
    31 #define GREP_OPT_l (1<<0)
    32 #define PRINT_FILES_WITH_MATCHES (opt & GREP_OPT_l)
    33 #define GREP_OPT_n (1<<1)
    34 #define PRINT_LINE_NUM (opt & GREP_OPT_n)
    35 #define GREP_OPT_q (1<<2)
    36 #define BE_QUIET (opt & GREP_OPT_q)
    37 #define GREP_OPT_v (1<<3)
    38 typedef char invert_search_t;
    39 static invert_search_t invert_search;
    40 #define GREP_OPT_s (1<<4)
    41 #define SUPPRESS_ERR_MSGS (opt & GREP_OPT_s)
    42 #define GREP_OPT_c (1<<5)
    43 #define PRINT_MATCH_COUNTS (opt & GREP_OPT_c)
    44 #define GREP_OPT_F (1<<6)
    45 #define FGREP_FLAG (opt & GREP_OPT_F)
    46 #define GREP_OPT_i (1<<7)
    47 #define GREP_OPT_H (1<<8)
    48 #define GREP_OPT_h (1<<9)
    49 #define GREP_OPT_e (1<<10)
    50 #define GREP_OPT_f (1<<11)
    51 #define GREP_OPT_L (1<<12)
    52 #define PRINT_FILES_WITHOUT_MATCHES ((opt & GREP_OPT_L) != 0)
    53 #if ENABLE_FEATURE_GREP_CONTEXT
    54 #define GREP_OPT_CONTEXT "A:B:C"
    55 #define GREP_OPT_A (1<<13)
    56 #define GREP_OPT_B (1<<14)
    57 #define GREP_OPT_C (1<<15)
    58 #define GREP_OPT_E (1<<16)
    59 #else
    60 #define GREP_OPT_CONTEXT ""
    61 #define GREP_OPT_A (0)
    62 #define GREP_OPT_B (0)
    63 #define GREP_OPT_C (0)
    64 #define GREP_OPT_E (1<<13)
    65 #endif
    66 #if ENABLE_FEATURE_GREP_EGREP_ALIAS
    67 # define OPT_EGREP "E"
    68 #else
    69 # define OPT_EGREP ""
    70 #endif
    71 
     26#define OPTSTR_GREP \
     27    "lnqvscFiHhe:f:Lorm:" \
     28    USE_FEATURE_GREP_CONTEXT("A:B:C:") \
     29    USE_FEATURE_GREP_EGREP_ALIAS("E") \
     30    USE_DESKTOP("w") \
     31    "aI"
     32/* ignored: -a "assume all files to be text" */
     33/* ignored: -I "assume binary files have no matches" */
     34
     35enum {
     36    OPTBIT_l, /* list matched file names only */
     37    OPTBIT_n, /* print line# */
     38    OPTBIT_q, /* quiet - exit(0) of first match */
     39    OPTBIT_v, /* invert the match, to select non-matching lines */
     40    OPTBIT_s, /* suppress errors about file open errors */
     41    OPTBIT_c, /* count matches per file (suppresses normal output) */
     42    OPTBIT_F, /* literal match */
     43    OPTBIT_i, /* case-insensitive */
     44    OPTBIT_H, /* force filename display */
     45    OPTBIT_h, /* inhibit filename display */
     46    OPTBIT_e, /* -e PATTERN */
     47    OPTBIT_f, /* -f FILE_WITH_PATTERNS */
     48    OPTBIT_L, /* list unmatched file names only */
     49    OPTBIT_o, /* show only matching parts of lines */
     50    OPTBIT_r, /* recurse dirs */
     51    OPTBIT_m, /* -m MAX_MATCHES */
     52    USE_FEATURE_GREP_CONTEXT(    OPTBIT_A ,) /* -A NUM: after-match context */
     53    USE_FEATURE_GREP_CONTEXT(    OPTBIT_B ,) /* -B NUM: before-match context */
     54    USE_FEATURE_GREP_CONTEXT(    OPTBIT_C ,) /* -C NUM: -A and -B combined */
     55    USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */
     56    USE_DESKTOP(                 OPTBIT_w ,) /* whole word match */
     57    OPT_l = 1 << OPTBIT_l,
     58    OPT_n = 1 << OPTBIT_n,
     59    OPT_q = 1 << OPTBIT_q,
     60    OPT_v = 1 << OPTBIT_v,
     61    OPT_s = 1 << OPTBIT_s,
     62    OPT_c = 1 << OPTBIT_c,
     63    OPT_F = 1 << OPTBIT_F,
     64    OPT_i = 1 << OPTBIT_i,
     65    OPT_H = 1 << OPTBIT_H,
     66    OPT_h = 1 << OPTBIT_h,
     67    OPT_e = 1 << OPTBIT_e,
     68    OPT_f = 1 << OPTBIT_f,
     69    OPT_L = 1 << OPTBIT_L,
     70    OPT_o = 1 << OPTBIT_o,
     71    OPT_r = 1 << OPTBIT_r,
     72    OPT_m = 1 << OPTBIT_m,
     73    OPT_A = USE_FEATURE_GREP_CONTEXT(    (1 << OPTBIT_A)) + 0,
     74    OPT_B = USE_FEATURE_GREP_CONTEXT(    (1 << OPTBIT_B)) + 0,
     75    OPT_C = USE_FEATURE_GREP_CONTEXT(    (1 << OPTBIT_C)) + 0,
     76    OPT_E = USE_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0,
     77    OPT_w = USE_DESKTOP(                 (1 << OPTBIT_w)) + 0,
     78};
     79
     80#define PRINT_FILES_WITH_MATCHES    (option_mask32 & OPT_l)
     81#define PRINT_LINE_NUM              (option_mask32 & OPT_n)
     82#define BE_QUIET                    (option_mask32 & OPT_q)
     83#define SUPPRESS_ERR_MSGS           (option_mask32 & OPT_s)
     84#define PRINT_MATCH_COUNTS          (option_mask32 & OPT_c)
     85#define FGREP_FLAG                  (option_mask32 & OPT_F)
     86#define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L)
     87
     88typedef unsigned char byte_t;
     89
     90static int max_matches;
    7291static int reflags;
    73 static int print_filename;
    74 
    75 #if ENABLE_FEATURE_GREP_CONTEXT
     92static byte_t invert_search;
     93static byte_t print_filename;
     94static byte_t open_errors;
     95
     96#if ENABLE_FEATURE_GREP_CONTEXT
     97static byte_t did_print_line;
    7698static int lines_before;
    7799static int lines_after;
     
    79101static int last_line_printed;
    80102#endif /* ENABLE_FEATURE_GREP_CONTEXT */
    81 
    82103/* globals used internally */
    83104static llist_t *pattern_head;   /* growable list of patterns to match */
    84 static char *cur_file;          /* the current file we are reading */
    85 
    86 typedef struct GREP_LIST_DATA {
     105static const char *cur_file;    /* the current file we are reading */
     106
     107typedef struct grep_list_data_t {
    87108    char *pattern;
    88109    regex_t preg;
     
    95116{
    96117#if ENABLE_FEATURE_GREP_CONTEXT
     118    /* Happens when we go to next file, immediately hit match
     119     * and try to print prev context... from prev file! Don't do it */
     120    if (linenum < 1)
     121        return;
    97122    /* possibly print the little '--' separator */
    98     if ((lines_before || lines_after) && last_line_printed &&
    99             last_line_printed < linenum - 1) {
     123    if ((lines_before || lines_after) && did_print_line &&
     124            last_line_printed != linenum - 1) {
    100125        puts("--");
    101126    }
     127    /* guard against printing "--" before first line of first file */
     128    did_print_line = 1;
    102129    last_line_printed = linenum;
    103130#endif
    104     if (print_filename > 0)
     131    if (print_filename)
    105132        printf("%s%c", cur_file, decoration);
    106133    if (PRINT_LINE_NUM)
    107134        printf("%i%c", linenum, decoration);
    108     puts(line);
    109 }
    110 
     135    /* Emulate weird GNU grep behavior with -ov */
     136    if ((option_mask32 & (OPT_v|OPT_o)) != (OPT_v|OPT_o))
     137        puts(line);
     138}
    111139
    112140static int grep_file(FILE *file)
    113141{
    114142    char *line;
    115     invert_search_t ret;
     143    byte_t ret;
    116144    int linenum = 0;
    117145    int nmatches = 0;
     146    regmatch_t regmatch;
    118147#if ENABLE_FEATURE_GREP_CONTEXT
    119148    int print_n_lines_after = 0;
    120149    int curpos = 0; /* track where we are in the circular 'before' buffer */
    121150    int idx = 0; /* used for iteration through the circular buffer */
     151#else
     152    enum { print_n_lines_after = 0 };
    122153#endif /* ENABLE_FEATURE_GREP_CONTEXT */
    123154
    124     while ((line = bb_get_chomped_line_from_file(file)) != NULL) {
     155    while ((line = xmalloc_getline(file)) != NULL) {
    125156        llist_t *pattern_ptr = pattern_head;
    126157        grep_list_data_t * gl;
     
    139170                 * invert search)
    140171                 */
    141                 if(!(gl->flg_mem_alocated_compiled & COMPILED)) {
     172                if (!(gl->flg_mem_alocated_compiled & COMPILED)) {
    142173                    gl->flg_mem_alocated_compiled |= COMPILED;
    143174                    xregcomp(&(gl->preg), gl->pattern, reflags);
    144175                }
    145                 ret |= regexec(&(gl->preg), line, 0, NULL, 0) == 0;
     176                regmatch.rm_so = 0;
     177                regmatch.rm_eo = 0;
     178                if (regexec(&(gl->preg), line, 1, &regmatch, 0) == 0) {
     179                    if (!(option_mask32 & OPT_w))
     180                        ret = 1;
     181                    else {
     182                        char c = ' ';
     183                        if (regmatch.rm_so)
     184                            c = line[regmatch.rm_so - 1];
     185                        if (!isalnum(c) && c != '_') {
     186                            c = line[regmatch.rm_eo];
     187                            if (!c || (!isalnum(c) && c != '_'))
     188                                ret = 1;
     189                        }
     190                    }
     191                }
    146192            }
    147193            pattern_ptr = pattern_ptr->link;
    148194        } /* while (pattern_ptr) */
    149195
    150         if ((ret ^ invert_search)) {
    151 
    152             if (PRINT_FILES_WITH_MATCHES || BE_QUIET)
    153                 free(line);
    154 
    155             /* if we found a match but were told to be quiet, stop here */
    156             if (BE_QUIET || PRINT_FILES_WITHOUT_MATCHES)
    157                 return -1;
    158 
    159                 /* keep track of matches */
    160                 nmatches++;
    161 
     196        if (ret ^ invert_search) {
     197            /* keep track of matches */
     198            nmatches++;
     199
     200            /* quiet/print (non)matching file names only? */
     201            if (option_mask32 & (OPT_q|OPT_l|OPT_L)) {
     202                free(line); /* we don't need line anymore */
     203                if (BE_QUIET) {
     204                    /* manpage says about -q:
     205                     * "exit immediately with zero status
     206                     * if any match is found,
     207                     * even if errors were detected" */
     208                    exit(0);
     209                }
    162210                /* if we're just printing filenames, we stop after the first match */
    163                 if (PRINT_FILES_WITH_MATCHES)
    164                     break;
    165 
    166                 /* print the matched line */
    167                 if (PRINT_MATCH_COUNTS == 0) {
    168 #if ENABLE_FEATURE_GREP_CONTEXT
    169                     int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1;
    170 
    171                     /* if we were told to print 'before' lines and there is at least
    172                      * one line in the circular buffer, print them */
    173                     if (lines_before && before_buf[prevpos] != NULL) {
    174                         int first_buf_entry_line_num = linenum - lines_before;
    175 
    176                         /* advance to the first entry in the circular buffer, and
    177                          * figure out the line number is of the first line in the
    178                          * buffer */
    179                         idx = curpos;
    180                         while (before_buf[idx] == NULL) {
    181                             idx = (idx + 1) % lines_before;
    182                             first_buf_entry_line_num++;
    183                         }
    184 
    185                         /* now print each line in the buffer, clearing them as we go */
    186                         while (before_buf[idx] != NULL) {
    187                             print_line(before_buf[idx], first_buf_entry_line_num, '-');
    188                             free(before_buf[idx]);
    189                             before_buf[idx] = NULL;
    190                             idx = (idx + 1) % lines_before;
    191                             first_buf_entry_line_num++;
    192                         }
     211                if (PRINT_FILES_WITH_MATCHES) {
     212                    puts(cur_file);
     213                    /* fall thru to "return 1" */
     214                }
     215                /* OPT_L aka PRINT_FILES_WITHOUT_MATCHES: return early */
     216                return 1; /* one match */
     217            }
     218
     219#if ENABLE_FEATURE_GREP_CONTEXT
     220            /* Were we printing context and saw next (unwanted) match? */
     221            if ((option_mask32 & OPT_m) && nmatches > max_matches)
     222                break;
     223#endif
     224
     225            /* print the matched line */
     226            if (PRINT_MATCH_COUNTS == 0) {
     227#if ENABLE_FEATURE_GREP_CONTEXT
     228                int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1;
     229
     230                /* if we were told to print 'before' lines and there is at least
     231                 * one line in the circular buffer, print them */
     232                if (lines_before && before_buf[prevpos] != NULL) {
     233                    int first_buf_entry_line_num = linenum - lines_before;
     234
     235                    /* advance to the first entry in the circular buffer, and
     236                     * figure out the line number is of the first line in the
     237                     * buffer */
     238                    idx = curpos;
     239                    while (before_buf[idx] == NULL) {
     240                        idx = (idx + 1) % lines_before;
     241                        first_buf_entry_line_num++;
    193242                    }
    194243
    195                     /* make a note that we need to print 'after' lines */
    196                     print_n_lines_after = lines_after;
     244                    /* now print each line in the buffer, clearing them as we go */
     245                    while (before_buf[idx] != NULL) {
     246                        print_line(before_buf[idx], first_buf_entry_line_num, '-');
     247                        free(before_buf[idx]);
     248                        before_buf[idx] = NULL;
     249                        idx = (idx + 1) % lines_before;
     250                        first_buf_entry_line_num++;
     251                    }
     252                }
     253
     254                /* make a note that we need to print 'after' lines */
     255                print_n_lines_after = lines_after;
    197256#endif
     257                if (option_mask32 & OPT_o) {
     258                    line[regmatch.rm_eo] = '\0';
     259                    print_line(line + regmatch.rm_so, linenum, ':');
     260                } else {
    198261                    print_line(line, linenum, ':');
    199262                }
    200263            }
    201 #if ENABLE_FEATURE_GREP_CONTEXT
    202             else { /* no match */
    203                 /* Add the line to the circular 'before' buffer */
    204                 if(lines_before) {
    205                     free(before_buf[curpos]);
    206                     before_buf[curpos] = bb_xstrdup(line);
    207                     curpos = (curpos + 1) % lines_before;
    208                 }
    209             }
    210 
     264        }
     265#if ENABLE_FEATURE_GREP_CONTEXT
     266        else { /* no match */
    211267            /* if we need to print some context lines after the last match, do so */
    212             if (print_n_lines_after && (last_line_printed != linenum)) {
     268            if (print_n_lines_after) {
    213269                print_line(line, linenum, '-');
    214270                print_n_lines_after--;
     271            } else if (lines_before) {
     272                /* Add the line to the circular 'before' buffer */
     273                free(before_buf[curpos]);
     274                before_buf[curpos] = line;
     275                curpos = (curpos + 1) % lines_before;
     276                /* avoid free(line) - we took line */
     277                line = NULL;
    215278            }
     279        }
     280
    216281#endif /* ENABLE_FEATURE_GREP_CONTEXT */
    217282        free(line);
    218     }
    219 
     283
     284        /* Did we print all context after last requested match? */
     285        if ((option_mask32 & OPT_m)
     286         && !print_n_lines_after && nmatches == max_matches)
     287            break;
     288    }
    220289
    221290    /* special-case file post-processing for options where we don't print line
     
    224293    /* grep -c: print [filename:]count, even if count is zero */
    225294    if (PRINT_MATCH_COUNTS) {
    226         if (print_filename > 0)
     295        if (print_filename)
    227296            printf("%s:", cur_file);
    228             printf("%d\n", nmatches);
    229     }
    230 
    231     /* grep -l: print just the filename, but only if we grepped the line in the file  */
    232     if (PRINT_FILES_WITH_MATCHES && nmatches > 0) {
    233         puts(cur_file);
    234     }
    235 
    236     /* grep -L: print just the filename, but only if we didn't grep the line in the file  */
    237     if (PRINT_FILES_WITHOUT_MATCHES && nmatches == 0) {
     297        printf("%d\n", nmatches);
     298    }
     299
     300    /* grep -L: print just the filename */
     301    if (PRINT_FILES_WITHOUT_MATCHES) {
     302        /* nmatches is zero, no need to check it:
     303         * we return 1 early if we detected a match
     304         * and PRINT_FILES_WITHOUT_MATCHES is set */
    238305        puts(cur_file);
    239306    }
     
    260327}
    261328
    262 
    263329static void load_regexes_from_file(llist_t *fopt)
    264330{
     
    266332    FILE *f;
    267333
    268     while(fopt) {
     334    while (fopt) {
    269335        llist_t *cur = fopt;
    270336        char *ffile = cur->data;
     
    272338        fopt = cur->link;
    273339        free(cur);
    274         f = bb_xfopen(ffile, "r");
    275         while ((line = bb_get_chomped_line_from_file(f)) != NULL) {
     340        f = xfopen(ffile, "r");
     341        while ((line = xmalloc_getline(f)) != NULL) {
    276342            llist_add_to(&pattern_head,
    277343                new_grep_list_data(line, PATTERN_MEM_A));
     
    280346}
    281347
    282 
     348static int file_action_grep(const char *filename, struct stat *statbuf, void* matched, int depth)
     349{
     350    FILE *file = fopen(filename, "r");
     351    if (file == NULL) {
     352        if (!SUPPRESS_ERR_MSGS)
     353            bb_perror_msg("%s", cur_file);
     354        open_errors = 1;
     355        return 0;
     356    }
     357    cur_file = filename;
     358    *(int*)matched += grep_file(file);
     359    fclose(file);
     360    return 1;
     361}
     362
     363static int grep_dir(const char *dir)
     364{
     365    int matched = 0;
     366    recursive_action(dir,
     367        /* recurse=yes */ ACTION_RECURSE |
     368        /* followLinks=no */
     369        /* depthFirst=yes */ ACTION_DEPTHFIRST,
     370        /* fileAction= */ file_action_grep,
     371        /* dirAction= */ NULL,
     372        /* userData= */ &matched,
     373        /* depth= */ 0);
     374    return matched;
     375}
     376
     377int grep_main(int argc, char **argv);
    283378int grep_main(int argc, char **argv)
    284379{
    285380    FILE *file;
    286381    int matched;
     382    char *mopt;
    287383    llist_t *fopt = NULL;
    288     int error_open_count = 0;
    289384
    290385    /* do normal option parsing */
    291386#if ENABLE_FEATURE_GREP_CONTEXT
    292   {
    293     char *junk;
    294387    char *slines_after;
    295388    char *slines_before;
    296389    char *Copt;
    297390
    298     bb_opt_complementally = "H-h:e::f::C-AB";
    299     opt = bb_getopt_ulflags(argc, argv,
    300         GREP_OPTS GREP_OPT_CONTEXT OPT_EGREP,
    301         &pattern_head, &fopt,
     391    opt_complementary = "H-h:e::f::C-AB";
     392    getopt32(argv,
     393        OPTSTR_GREP,
     394        &pattern_head, &fopt, &mopt,
    302395        &slines_after, &slines_before, &Copt);
    303396
    304     if(opt & GREP_OPT_C) {
    305         /* C option unseted A and B options, but next -A or -B
    306            may be ovewrite own option */
    307         if(!(opt & GREP_OPT_A))         /* not overwtited */
     397    if (option_mask32 & OPT_C) {
     398        /* -C unsets prev -A and -B, but following -A or -B
     399           may override it */
     400        if (!(option_mask32 & OPT_A)) /* not overridden */
    308401            slines_after = Copt;
    309         if(!(opt & GREP_OPT_B))         /* not overwtited */
     402        if (!(option_mask32 & OPT_B)) /* not overridden */
    310403            slines_before = Copt;
    311         opt |= GREP_OPT_A|GREP_OPT_B;   /* set for parse now */
    312     }
    313     if(opt & GREP_OPT_A) {
    314         lines_after = strtoul(slines_after, &junk, 10);
    315         if(*junk != '\0')
    316             bb_error_msg_and_die(bb_msg_invalid_arg, slines_after, "-A");
    317     }
    318     if(opt & GREP_OPT_B) {
    319         lines_before = strtoul(slines_before, &junk, 10);
    320         if(*junk != '\0')
    321             bb_error_msg_and_die(bb_msg_invalid_arg, slines_before, "-B");
    322     }
    323     /* sanity checks after parse may be invalid numbers ;-) */
    324     if ((opt & (GREP_OPT_c|GREP_OPT_q|GREP_OPT_l|GREP_OPT_L))) {
    325         opt &= ~GREP_OPT_n;
     404        option_mask32 |= OPT_A|OPT_B; /* for parser */
     405    }
     406    if (option_mask32 & OPT_A) {
     407        lines_after = xatoi_u(slines_after);
     408    }
     409    if (option_mask32 & OPT_B) {
     410        lines_before = xatoi_u(slines_before);
     411    }
     412    /* sanity checks */
     413    if (option_mask32 & (OPT_c|OPT_q|OPT_l|OPT_L)) {
     414        option_mask32 &= ~OPT_n;
    326415        lines_before = 0;
    327416        lines_after = 0;
    328     } else if(lines_before > 0)
    329         before_buf = (char **)xcalloc(lines_before, sizeof(char *));
    330   }
     417    } else if (lines_before > 0)
     418        before_buf = xzalloc(lines_before * sizeof(char *));
    331419#else
    332420    /* with auto sanity checks */
    333     bb_opt_complementally = "H-h:e::f::c-n:q-n:l-n";
    334     opt = bb_getopt_ulflags(argc, argv, GREP_OPTS OPT_EGREP,
    335         &pattern_head, &fopt);
     421    opt_complementary = "H-h:e::f::c-n:q-n:l-n";
     422    getopt32(argv, OPTSTR_GREP,
     423        &pattern_head, &fopt, &mopt);
    336424#endif
    337     invert_search = (opt & GREP_OPT_v) != 0;        /* 0 | 1 */
    338 
    339     if(opt & GREP_OPT_H)
    340         print_filename++;
    341     if(opt & GREP_OPT_h)
    342         print_filename--;
     425    if (option_mask32 & OPT_m) {
     426        max_matches = xatoi_u(mopt);
     427    }
     428    invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */
     429
    343430    if (pattern_head != NULL) {
    344         /* convert char *argv[] to grep_list_data_t */
     431        /* convert char **argv to grep_list_data_t */
    345432        llist_t *cur;
    346433
    347         for(cur = pattern_head; cur; cur = cur->link)
     434        for (cur = pattern_head; cur; cur = cur->link)
    348435            cur->data = new_grep_list_data(cur->data, 0);
    349436    }
    350     if(opt & GREP_OPT_f)
     437    if (option_mask32 & OPT_f)
    351438        load_regexes_from_file(fopt);
    352439
    353     if(ENABLE_FEATURE_GREP_FGREP_ALIAS && bb_applet_name[0] == 'f')
    354         opt |= GREP_OPT_F;
    355 
    356     if(ENABLE_FEATURE_GREP_EGREP_ALIAS &&
    357             (bb_applet_name[0] == 'e' || (opt & GREP_OPT_E)))
    358         reflags = REG_EXTENDED | REG_NOSUB;
    359     else
     440    if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f')
     441        option_mask32 |= OPT_F;
     442
     443    if (!(option_mask32 & (OPT_o | OPT_w)))
    360444        reflags = REG_NOSUB;
    361445
    362     if(opt & GREP_OPT_i)
     446    if (ENABLE_FEATURE_GREP_EGREP_ALIAS &&
     447            (applet_name[0] == 'e' || (option_mask32 & OPT_E)))
     448        reflags |= REG_EXTENDED;
     449
     450    if (option_mask32 & OPT_i)
    363451        reflags |= REG_ICASE;
    364452
     
    369457     * argv[optind] should be the pattern. no pattern, no worky */
    370458    if (pattern_head == NULL) {
     459        char *pattern;
    371460        if (*argv == NULL)
    372461            bb_show_usage();
    373         else {
    374             char *pattern = new_grep_list_data(*argv++, 0);
    375 
    376             llist_add_to(&pattern_head, pattern);
    377             argc--;
    378         }
     462        pattern = new_grep_list_data(*argv++, 0);
     463        llist_add_to(&pattern_head, pattern);
     464        argc--;
    379465    }
    380466
    381467    /* argv[(optind)..(argc-1)] should be names of file to grep through. If
    382      * there is more than one file to grep, we will print the filenames */
    383     if (argc > 1) {
    384         print_filename++;
     468     * there is more than one file to grep, we will print the filenames. */
     469    if (argc > 1)
     470        print_filename = 1;
     471    /* -H / -h of course override */
     472    if (option_mask32 & OPT_H)
     473        print_filename = 1;
     474    if (option_mask32 & OPT_h)
     475        print_filename = 0;
    385476
    386477    /* If no files were specified, or '-' was specified, take input from
    387478     * stdin. Otherwise, we grep through all the files specified. */
    388     } else if (argc == 0) {
     479    if (argc == 0)
    389480        argc++;
    390     }
    391481    matched = 0;
    392482    while (argc--) {
    393483        cur_file = *argv++;
    394         if(!cur_file || (*cur_file == '-' && !cur_file[1])) {
     484        file = stdin;
     485        if (!cur_file || (*cur_file == '-' && !cur_file[1])) {
    395486            cur_file = "(standard input)";
    396             file = stdin;
    397487        } else {
     488            if (option_mask32 & OPT_r) {
     489                struct stat st;
     490                if (stat(cur_file, &st) == 0 && S_ISDIR(st.st_mode)) {
     491                    if (!(option_mask32 & OPT_h))
     492                        print_filename = 1;
     493                    matched += grep_dir(cur_file);
     494                    goto grep_done;
     495                }
     496            }
     497            /* else: fopen(dir) will succeed, but reading won't */
    398498            file = fopen(cur_file, "r");
     499            if (file == NULL) {
     500                if (!SUPPRESS_ERR_MSGS)
     501                    bb_perror_msg("%s", cur_file);
     502                open_errors = 1;
     503                continue;
     504            }
    399505        }
    400         if (file == NULL) {
    401             if (!SUPPRESS_ERR_MSGS)
    402                 bb_perror_msg("%s", cur_file);
    403             error_open_count++;
    404         } else {
    405             matched += grep_file(file);
    406             if(matched < 0) {
    407                 /* we found a match but were told to be quiet, stop here and
    408                 * return success */
    409                 break;
    410             }
    411             fclose(file);
    412         }
     506        matched += grep_file(file);
     507        fclose_if_not_stdin(file);
     508 grep_done: ;
    413509    }
    414510
     
    421517
    422518            pattern_head = pattern_head->link;
    423             if((gl->flg_mem_alocated_compiled & PATTERN_MEM_A))
     519            if ((gl->flg_mem_alocated_compiled & PATTERN_MEM_A))
    424520                free(gl->pattern);
    425             if((gl->flg_mem_alocated_compiled & COMPILED))
     521            if ((gl->flg_mem_alocated_compiled & COMPILED))
    426522                regfree(&(gl->preg));
     523            free(gl);
    427524            free(pattern_head_ptr);
    428525        }
    429526    }
    430527    /* 0 = success, 1 = failed, 2 = error */
    431     /* If the -q option is specified, the exit status shall be zero
    432      * if an input line is selected, even if an error was detected.  */
    433     if(BE_QUIET && matched)
    434         return 0;
    435     if(error_open_count)
     528    if (open_errors)
    436529        return 2;
    437530    return !matched; /* invert return value 0 = success, 1 = failed */
  • branches/2.2.5/mindi-busybox/findutils/xargs.c

    r821 r1765  
    1818 */
    1919
    20 #include "busybox.h"
    21 #include <stdio.h>
    22 #include <stdlib.h>
    23 #include <string.h>
    24 #include <unistd.h>
    25 #include <getopt.h>
    26 #include <errno.h>
    27 #include <fcntl.h>
    28 #include <sys/types.h>
    29 #include <sys/wait.h>
     20#include "libbb.h"
     21
     22/* This is a NOEXEC applet. Be very careful! */
     23
    3024
    3125/* COMPAT:  SYSV version defaults size (and has a max value of) to 470.
     
    4034
    4135#ifdef TEST
    42 # ifndef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
    43 #  define CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
     36# ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
     37#  define ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 1
    4438# endif
    45 # ifndef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
    46 #  define CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
     39# ifndef ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
     40#  define ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 1
    4741# endif
    48 # ifndef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
    49 #  define CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
     42# ifndef ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
     43#  define ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT 1
    5044# endif
    51 # ifndef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
    52 #  define CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
     45# ifndef ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
     46#  define ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 1
    5347# endif
    5448#endif
    5549
    5650/*
    57    This function have special algorithm.
    58    Don`t use fork and include to main!
     51   This function has special algorithm.
     52   Don't use fork and include to main!
    5953*/
    60 static int xargs_exec(char *const *args)
    61 {
    62     pid_t p;
    63     volatile int exec_errno = 0;    /* shared vfork stack */
    64 
    65     if ((p = vfork()) >= 0) {
    66         if (p == 0) {
    67             /* vfork -- child */
    68             execvp(args[0], args);
    69             exec_errno = errno;     /* set error to shared stack */
    70             _exit(1);
    71         } else {
    72             /* vfork -- parent */
    73             int status;
    74 
    75             while (wait(&status) == (pid_t) - 1)
    76                 if (errno != EINTR)
    77                     break;
    78             if (exec_errno) {
    79                 errno = exec_errno;
    80                 bb_perror_msg("%s", args[0]);
    81                 return exec_errno == ENOENT ? 127 : 126;
    82             } else {
    83                 if (WEXITSTATUS(status) == 255) {
    84                     bb_error_msg("%s: exited with status 255; aborting", args[0]);
    85                     return 124;
    86                 }
    87                 if (WIFSTOPPED(status)) {
    88                     bb_error_msg("%s: stopped by signal %d",
    89                         args[0], WSTOPSIG(status));
    90                     return 125;
    91                 }
    92                 if (WIFSIGNALED(status)) {
    93                     bb_error_msg("%s: terminated by signal %d",
    94                         args[0], WTERMSIG(status));
    95                     return 125;
    96                 }
    97                 if (WEXITSTATUS(status) != 0)
    98                     return 123;
    99                 return 0;
    100             }
    101         }
    102     } else {
    103         bb_perror_msg_and_die("vfork");
    104     }
    105 }
    106 
    107 
    108 typedef struct xlist_s {
    109     char *data;
    110     size_t lenght;
    111     struct xlist_s *link;
     54static int xargs_exec(char **args)
     55{
     56    int status;
     57
     58    status = spawn_and_wait(args);
     59    if (status < 0) {
     60        bb_perror_msg("%s", args[0]);
     61        return errno == ENOENT ? 127 : 126;
     62    }
     63    if (status == 255) {
     64        bb_error_msg("%s: exited with status 255; aborting", args[0]);
     65        return 124;
     66    }
     67/* Huh? I think we won't see this, ever. We don't wait with WUNTRACED!
     68    if (WIFSTOPPED(status)) {
     69        bb_error_msg("%s: stopped by signal %d",
     70            args[0], WSTOPSIG(status));
     71        return 125;
     72    }
     73*/
     74    if (status >= 1000) {
     75        bb_error_msg("%s: terminated by signal %d",
     76            args[0], status - 1000);
     77        return 125;
     78    }
     79    if (status)
     80        return 123;
     81    return 0;
     82}
     83
     84
     85typedef struct xlist_t {
     86    struct xlist_t *link;
     87    size_t length;
     88    char xstr[1];
    11289} xlist_t;
    11390
    114 static int eof_stdin_detected;
     91static smallint eof_stdin_detected;
    11592
    11693#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
    117 #define ISSPACE(c) (ISBLANK (c) || (c) == '\n' || (c) == '\r' \
     94#define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \
    11895            || (c) == '\f' || (c) == '\v')
    11996
    120 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
    121 static xlist_t *process_stdin(xlist_t * list_arg,
     97#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
     98static xlist_t *process_stdin(xlist_t *list_arg,
    12299    const char *eof_str, size_t mc, char *buf)
    123100{
     
    129106    char *s = NULL;         /* start word */
    130107    char *p = NULL;         /* pointer to end word */
    131     char q = 0;             /* quote char */
     108    char q = '\0';          /* quote char */
    132109    char state = NORM;
    133110    char eof_str_detected = 0;
     
    137114    xlist_t *prev;
    138115
    139     for (prev = cur = list_arg; cur; cur = cur->link) {
    140         line_l += cur->lenght;  /* previous allocated */
    141         if (prev != cur)
    142             prev = prev->link;
     116    prev = cur = list_arg;
     117    while (1) {
     118        if (!cur) break;
     119        prev = cur;
     120        line_l += cur->length;
     121        cur = cur->link;
    143122    }
    144123
     
    146125        c = getchar();
    147126        if (c == EOF) {
    148             eof_stdin_detected++;
     127            eof_stdin_detected = 1;
    149128            if (s)
    150129                goto unexpected_eof;
     
    157136            goto set;
    158137        } else if (state == QUOTE) {
    159             if (c == q) {
    160                 q = 0;
    161                 state = NORM;
    162             } else {
     138            if (c != q)
    163139                goto set;
    164             }
    165         } else { /* if(state == NORM) */
    166 
     140            q = '\0';
     141            state = NORM;
     142        } else { /* if (state == NORM) */
    167143            if (ISSPACE(c)) {
    168144                if (s) {
    169 unexpected_eof:
     145 unexpected_eof:
    170146                    state = SPACE;
    171                     c = 0;
     147                    c = '\0';
    172148                    goto set;
    173149                }
     
    181157                    state = QUOTE;
    182158                } else {
    183 set:
     159 set:
    184160                    if ((size_t)(p - buf) >= mc)
    185161                        bb_error_msg_and_die("argument line too long");
     
    195171            /* word loaded */
    196172            if (eof_str) {
    197                 eof_str_detected = strcmp(s, eof_str) == 0;
     173                eof_str_detected = (strcmp(s, eof_str) == 0);
    198174            }
    199175            if (!eof_str_detected) {
    200                 size_t lenght = (p - buf);
    201 
    202                 cur = xmalloc(sizeof(xlist_t) + lenght);
    203                 cur->data = memcpy(cur + 1, s, lenght);
    204                 cur->lenght = lenght;
     176                size_t length = (p - buf);
     177                /* Dont xzalloc - it can be quite big */
     178                cur = xmalloc(offsetof(xlist_t, xstr) + length);
    205179                cur->link = NULL;
     180                cur->length = length;
     181                memcpy(cur->xstr, s, length);
    206182                if (prev == NULL) {
    207183                    list_arg = cur;
     
    210186                }
    211187                prev = cur;
    212                 line_l += lenght;
     188                line_l += length;
    213189                if (line_l > mc) {
    214190                    /* stop memory usage :-) */
     
    224200#else
    225201/* The variant does not support single quotes, double quotes or backslash */
    226 static xlist_t *process_stdin(xlist_t * list_arg,
    227     const char *eof_str, size_t mc, char *buf)
     202static xlist_t *process_stdin(xlist_t *list_arg,
     203        const char *eof_str, size_t mc, char *buf)
    228204{
    229205
    230206    int c;                  /* current char */
    231     int eof_str_detected = 0;
     207    char eof_str_detected = 0;
    232208    char *s = NULL;         /* start word */
    233209    char *p = NULL;         /* pointer to end word */
     
    236212    xlist_t *prev;
    237213
    238     for (prev = cur = list_arg; cur; cur = cur->link) {
    239         line_l += cur->lenght;  /* previous allocated */
    240         if (prev != cur)
    241             prev = prev->link;
     214    prev = cur = list_arg;
     215    while (1) {
     216        if (!cur) break;
     217        prev = cur;
     218        line_l += cur->length;
     219        cur = cur->link;
    242220    }
    243221
     
    245223        c = getchar();
    246224        if (c == EOF) {
    247             eof_stdin_detected++;
     225            eof_stdin_detected = 1;
    248226        }
    249227        if (eof_str_detected)
     
    258236        if ((p - buf) >= mc)
    259237            bb_error_msg_and_die("argument line too long");
    260         *p++ = c == EOF ? 0 : c;
     238        *p++ = (c == EOF ? '\0' : c);
    261239        if (c == EOF) { /* word's delimiter or EOF detected */
    262240            /* word loaded */
    263241            if (eof_str) {
    264                 eof_str_detected = strcmp(s, eof_str) == 0;
     242                eof_str_detected = (strcmp(s, eof_str) == 0);
    265243            }
    266244            if (!eof_str_detected) {
    267                 size_t lenght = (p - buf);
    268 
    269                 cur = xmalloc(sizeof(xlist_t) + lenght);
    270                 cur->data = memcpy(cur + 1, s, lenght);
    271                 cur->lenght = lenght;
     245                size_t length = (p - buf);
     246                /* Dont xzalloc - it can be quite big */
     247                cur = xmalloc(offsetof(xlist_t, xstr) + length);
    272248                cur->link = NULL;
     249                cur->length = length;
     250                memcpy(cur->xstr, s, length);
    273251                if (prev == NULL) {
    274252                    list_arg = cur;
     
    277255                }
    278256                prev = cur;
    279                 line_l += lenght;
     257                line_l += length;
    280258                if (line_l > mc) {
    281259                    /* stop memory usage :-) */
     
    288266    return list_arg;
    289267}
    290 #endif /* CONFIG_FEATURE_XARGS_SUPPORT_QUOTES */
    291 
    292 
    293 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
     268#endif /* FEATURE_XARGS_SUPPORT_QUOTES */
     269
     270
     271#if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
    294272/* Prompt the user for a response, and
    295273   if the user responds affirmatively, return true;
    296    otherwise, return false. Used "/dev/tty", not stdin. */
     274   otherwise, return false. Uses "/dev/tty", not stdin. */
    297275static int xargs_ask_confirmation(void)
    298276{
    299     static FILE *tty_stream;
     277    FILE *tty_stream;
    300278    int c, savec;
    301279
    302     if (!tty_stream) {
    303         tty_stream = bb_xfopen(CURRENT_TTY, "r");
    304         /* pranoidal security by vodz */
    305         fcntl(fileno(tty_stream), F_SETFD, FD_CLOEXEC);
    306     }
     280    tty_stream = xfopen(CURRENT_TTY, "r");
    307281    fputs(" ?...", stderr);
    308282    fflush(stderr);
     
    310284    while (c != EOF && c != '\n')
    311285        c = getc(tty_stream);
    312     if (savec == 'y' || savec == 'Y')
    313         return 1;
    314     return 0;
    315 }
    316 
    317 # define OPT_INC_P 1
     286    fclose(tty_stream);
     287    return (savec == 'y' || savec == 'Y');
     288}
    318289#else
    319 # define OPT_INC_P 0
    320290# define xargs_ask_confirmation() 1
    321 #endif /* CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION */
    322 
    323 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
    324 # define OPT_INC_X 1
    325 #else
    326 # define OPT_INC_X 0
    327 #endif
    328 
    329 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
    330 static xlist_t *process0_stdin(xlist_t * list_arg, const char *eof_str ATTRIBUTE_UNUSED,
    331                                size_t mc, char *buf)
     291#endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */
     292
     293#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
     294static xlist_t *process0_stdin(xlist_t *list_arg,
     295        const char *eof_str ATTRIBUTE_UNUSED, size_t mc, char *buf)
    332296{
    333297    int c;                  /* current char */
     
    338302    xlist_t *prev;
    339303
    340     for (prev = cur = list_arg; cur; cur = cur->link) {
    341         line_l += cur->lenght;  /* previous allocated */
    342         if (prev != cur)
    343             prev = prev->link;
     304    prev = cur = list_arg;
     305    while (1) {
     306        if (!cur) break;
     307        prev = cur;
     308        line_l += cur->length;
     309        cur = cur->link;
    344310    }
    345311
     
    347313        c = getchar();
    348314        if (c == EOF) {
    349             eof_stdin_detected++;
     315            eof_stdin_detected = 1;
    350316            if (s == NULL)
    351317                break;
    352             c = 0;
     318            c = '\0';
    353319        }
    354320        if (s == NULL)
     
    357323            bb_error_msg_and_die("argument line too long");
    358324        *p++ = c;
    359         if (c == 0) {   /* word's delimiter or EOF detected */
     325        if (c == '\0') {   /* word's delimiter or EOF detected */
    360326            /* word loaded */
    361             size_t lenght = (p - buf);
    362 
    363             cur = xmalloc(sizeof(xlist_t) + lenght);
    364             cur->data = memcpy(cur + 1, s, lenght);
    365             cur->lenght = lenght;
     327            size_t length = (p - buf);
     328            /* Dont xzalloc - it can be quite big */
     329            cur = xmalloc(offsetof(xlist_t, xstr) + length);
    366330            cur->link = NULL;
     331            cur->length = length;
     332            memcpy(cur->xstr, s, length);
    367333            if (prev == NULL) {
    368334                list_arg = cur;
     
    371337            }
    372338            prev = cur;
    373             line_l += lenght;
     339            line_l += length;
    374340            if (line_l > mc) {
    375341                /* stop memory usage :-) */
     
    381347    return list_arg;
    382348}
    383 
    384 # define READ_ARGS(l, e, nmc, mc) (*read_args)(l, e, nmc, mc)
    385 # define OPT_INC_0 1    /* future use */
    386 #else
    387 # define OPT_INC_0 0    /* future use */
    388 # define READ_ARGS(l, e, nmc, mc) process_stdin(l, e, nmc, mc)
    389 #endif /* CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM */
    390 
    391 
    392 #define OPT_VERBOSE     (1<<0)
    393 #define OPT_NO_EMPTY    (1<<1)
    394 #define OPT_UPTO_NUMBER (1<<2)
    395 #define OPT_UPTO_SIZE   (1<<3)
    396 #define OPT_EOF_STRING  (1<<4)
    397 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
    398 #define OPT_INTERACTIVE (1<<5)
    399 #else
    400 #define OPT_INTERACTIVE (0)     /* require for algorithm &| */
    401 #endif
    402 #define OPT_TERMINATE   (1<<(5+OPT_INC_P))
    403 #define OPT_ZEROTERM    (1<<(5+OPT_INC_P+OPT_INC_X))
    404 /* next future
    405 #define OPT_NEXT_OTHER  (1<<(5+OPT_INC_P+OPT_INC_X+OPT_INC_0))
    406 */
    407 
     349#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
     350
     351/* Correct regardless of combination of CONFIG_xxx */
     352enum {
     353    OPTBIT_VERBOSE = 0,
     354    OPTBIT_NO_EMPTY,
     355    OPTBIT_UPTO_NUMBER,
     356    OPTBIT_UPTO_SIZE,
     357    OPTBIT_EOF_STRING,
     358    USE_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
     359    USE_FEATURE_XARGS_SUPPORT_TERMOPT(     OPTBIT_TERMINATE  ,)
     360    USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(   OPTBIT_ZEROTERM   ,)
     361
     362    OPT_VERBOSE     = 1<<OPTBIT_VERBOSE    ,
     363    OPT_NO_EMPTY    = 1<<OPTBIT_NO_EMPTY   ,
     364    OPT_UPTO_NUMBER = 1<<OPTBIT_UPTO_NUMBER,
     365    OPT_UPTO_SIZE   = 1<<OPTBIT_UPTO_SIZE  ,
     366    OPT_EOF_STRING  = 1<<OPTBIT_EOF_STRING ,
     367    OPT_INTERACTIVE = USE_FEATURE_XARGS_SUPPORT_CONFIRMATION((1<<OPTBIT_INTERACTIVE)) + 0,
     368    OPT_TERMINATE   = USE_FEATURE_XARGS_SUPPORT_TERMOPT(     (1<<OPTBIT_TERMINATE  )) + 0,
     369    OPT_ZEROTERM    = USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(   (1<<OPTBIT_ZEROTERM   )) + 0,
     370};
     371#define OPTION_STR "+trn:s:e::" \
     372    USE_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
     373    USE_FEATURE_XARGS_SUPPORT_TERMOPT(     "x") \
     374    USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(   "0")
     375
     376int xargs_main(int argc, char **argv);
    408377int xargs_main(int argc, char **argv)
    409378{
    410379    char **args;
    411     int i, a, n;
     380    int i, n;
    412381    xlist_t *list = NULL;
    413382    xlist_t *cur;
     
    418387    long orig_arg_max;
    419388    const char *eof_str = "_";
    420     unsigned long opt;
     389    unsigned opt;
    421390    size_t n_max_chars;
    422 
    423 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
    424     xlist_t *(*read_args) (xlist_t *, const char *, size_t, char *) = process_stdin;
     391#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
     392    xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin;
     393#else
     394#define read_args process_stdin
    425395#endif
    426396
    427 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
    428     bb_opt_complementally = "pt";
    429 #endif
    430 
    431     opt = bb_getopt_ulflags(argc, argv, "+trn:s:e::"
    432 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
    433     "p"
    434 #endif
    435 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
    436     "x"
    437 #endif
    438 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
    439     "0"
    440 #endif
    441     ,&max_args, &max_chars, &eof_str);
    442 
    443     a = argc - optind;
     397    opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &eof_str);
     398
     399    if (opt & OPT_ZEROTERM)
     400        USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
     401
    444402    argv += optind;
    445     if (a == 0) {
     403    argc -= optind;
     404    if (!argc) {
    446405        /* default behavior is to echo all the filenames */
    447         *argv = "echo";
    448         a++;
     406        *argv = (char*)"echo";
     407        argc++;
    449408    }
    450409
     
    452411    if (orig_arg_max == -1)
    453412        orig_arg_max = LONG_MAX;
    454     orig_arg_max -= 2048;   /* POSIX.2 requires subtracting 2048.  */
    455     if ((opt & OPT_UPTO_SIZE)) {
    456         n_max_chars = bb_xgetularg10_bnd(max_chars, 1, orig_arg_max);
    457         for (i = 0; i < a; i++) {
     413    orig_arg_max -= 2048;   /* POSIX.2 requires subtracting 2048 */
     414
     415    if (opt & OPT_UPTO_SIZE) {
     416        n_max_chars = xatoul_range(max_chars, 1, orig_arg_max);
     417        for (i = 0; i < argc; i++) {
    458418            n_chars += strlen(*argv) + 1;
    459419        }
    460420        if (n_max_chars < n_chars) {
    461             bb_error_msg_and_die("can not fit single argument within argument list size limit");
     421            bb_error_msg_and_die("cannot fit single argument within argument list size limit");
    462422        }
    463423        n_max_chars -= n_chars;
     
    473433    max_chars = xmalloc(n_max_chars);
    474434
    475     if ((opt & OPT_UPTO_NUMBER)) {
    476         n_max_arg = bb_xgetularg10_bnd(max_args, 1, INT_MAX);
     435    if (opt & OPT_UPTO_NUMBER) {
     436        n_max_arg = xatoul_range(max_args, 1, INT_MAX);
    477437    } else {
    478438        n_max_arg = n_max_chars;
    479439    }
    480440
    481 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
    482     if (opt & OPT_ZEROTERM)
    483         read_args = process0_stdin;
    484 #endif
    485 
    486     while ((list = READ_ARGS(list, eof_str, n_max_chars, max_chars)) != NULL ||
    487         (opt & OPT_NO_EMPTY) == 0)
     441    while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL ||
     442        !(opt & OPT_NO_EMPTY))
    488443    {
    489444        opt |= OPT_NO_EMPTY;
    490445        n = 0;
    491446        n_chars = 0;
    492 #ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
     447#if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
    493448        for (cur = list; cur;) {
    494             n_chars += cur->lenght;
     449            n_chars += cur->length;
    495450            n++;
    496451            cur = cur->link;
     
    503458#else
    504459        for (cur = list; cur; cur = cur->link) {
    505             n_chars += cur->lenght;
     460            n_chars += cur->length;
    506461            n++;
    507462            if (n_chars > n_max_chars || n == n_max_arg) {
     
    509464            }
    510465        }
    511 #endif /* CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT */
    512 
    513         /* allocating pointers for execvp:
    514            a*arg, n*arg from stdin, NULL */
    515         args = xcalloc(n + a + 1, sizeof(char *));
    516 
    517         /* Store the command to be executed
     466#endif /* FEATURE_XARGS_SUPPORT_TERMOPT */
     467
     468        /* allocate pointers for execvp:
     469           argc*arg, n*arg from stdin, NULL */
     470        args = xzalloc((n + argc + 1) * sizeof(char *));
     471
     472        /* store the command to be executed
    518473           (taken from the command line) */
    519         for (i = 0; i < a; i++)
     474        for (i = 0; i < argc; i++)
    520475            args[i] = argv[i];
    521476        /* (taken from stdin) */
    522477        for (cur = list; n; cur = cur->link) {
    523             args[i++] = cur->data;
     478            args[i++] = cur->xstr;
    524479            n--;
    525480        }
    526481
    527         if ((opt & (OPT_INTERACTIVE | OPT_VERBOSE))) {
     482        if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
    528483            for (i = 0; args[i]; i++) {
    529484                if (i)
     
    531486                fputs(args[i], stderr);
    532487            }
    533             if ((opt & OPT_INTERACTIVE) == 0)
     488            if (!(opt & OPT_INTERACTIVE))
    534489                fputc('\n', stderr);
    535490        }
    536         if ((opt & OPT_INTERACTIVE) == 0 || xargs_ask_confirmation() != 0) {
     491        if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
    537492            child_error = xargs_exec(args);
    538493        }
    539494
    540495        /* clean up */
    541         for (i = a; args[i]; i++) {
     496        for (i = argc; args[i]; i++) {
    542497            cur = list;
    543498            list = list->link;
     
    549504        }
    550505    }
    551 #ifdef CONFIG_FEATURE_CLEAN_UP
    552     free(max_chars);
    553 #endif
     506    if (ENABLE_FEATURE_CLEAN_UP)
     507        free(max_chars);
    554508    return child_error;
    555509}
     
    558512#ifdef TEST
    559513
    560 const char *bb_applet_name = "debug stuff usage";
     514const char *applet_name = "debug stuff usage";
    561515
    562516void bb_show_usage(void)
    563517{
    564518    fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
    565         bb_applet_name);
     519        applet_name);
    566520    exit(1);
    567521}
Note: See TracChangeset for help on using the changeset viewer.