Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (13 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File:
1 edited

Legend:

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

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