Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/findutils


Ignore:
Timestamp:
Dec 20, 2016, 4:07:32 PM (7 years ago)
Author:
Bruno Cornec
Message:

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

Location:
branches/3.3
Files:
3 edited
1 copied

Legend:

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

    r3232 r3621  
    138138//config:     the files matched.
    139139//config:
     140//config:config FEATURE_FIND_EXEC_PLUS
     141//config:   bool "Enable -exec ... {} +"
     142//config:   default y
     143//config:   depends on FEATURE_FIND_EXEC
     144//config:   help
     145//config:     Support the 'find -exec ... {} +' option for executing commands
     146//config:     for all matched files at once.
     147//config:     Without this option, -exec + is a synonym for -exec ;
     148//config:     (IOW: it works correctly, but without expected speedup)
     149//config:
    140150//config:config FEATURE_FIND_USER
    141151//config:   bool "Enable -user: username/uid matching"
     
    232242
    233243//usage:#define find_trivial_usage
    234 //usage:       "[PATH]... [OPTIONS] [ACTIONS]"
     244//usage:       "[-HL] [PATH]... [OPTIONS] [ACTIONS]"
    235245//usage:#define find_full_usage "\n\n"
    236246//usage:       "Search for files and perform actions on them.\n"
    237247//usage:       "First failed action stops processing of current file.\n"
    238248//usage:       "Defaults: PATH is current directory, action is '-print'\n"
    239 //usage:     "\n    -follow     Follow symlinks"
     249//usage:     "\n    -L,-follow  Follow symlinks"
     250//usage:     "\n    -H      ...on command line only"
    240251//usage:    IF_FEATURE_FIND_XDEV(
    241252//usage:     "\n    -xdev       Don't descend directories on other filesystems"
     
    319330//usage:     "\n            file name. Fails if CMD exits with nonzero"
    320331//usage:    )
     332//usage:    IF_FEATURE_FIND_EXEC_PLUS(
     333//usage:     "\n    -exec CMD ARG + Run CMD with {} replaced by list of file names"
     334//usage:    )
    321335//usage:    IF_FEATURE_FIND_DELETE(
    322336//usage:     "\n    -delete     Delete current file/directory. Turns on -depth option"
     
    329343#include <fnmatch.h>
    330344#include "libbb.h"
     345#include "common_bufsiz.h"
    331346#if ENABLE_FEATURE_FIND_REGEX
    332347# include "xregex.h"
     
    337352#endif
    338353
    339 #define dbg(...) ((void)0)
    340 /* #define dbg(...) bb_error_msg(__VA_ARGS__) */
     354#if 1
     355# define dbg(...) ((void)0)
     356#else
     357# define dbg(...) bb_error_msg(__VA_ARGS__)
     358#endif
     359
    341360
    342361/* This is a NOEXEC applet. Be very careful! */
     
    375394IF_FEATURE_FIND_PRUNE(  ACTS(prune))
    376395IF_FEATURE_FIND_DELETE( ACTS(delete))
    377 IF_FEATURE_FIND_EXEC(   ACTS(exec,  char **exec_argv; unsigned *subst_count; int exec_argc;))
     396IF_FEATURE_FIND_EXEC(   ACTS(exec,
     397                char **exec_argv; /* -exec ARGS */
     398                unsigned *subst_count;
     399                int exec_argc; /* count of ARGS */
     400                IF_FEATURE_FIND_EXEC_PLUS(
     401                    /*
     402                     * filelist is NULL if "exec ;"
     403                     * non-NULL if "exec +"
     404                     */
     405                    char **filelist;
     406                    int filelist_idx;
     407                    int file_len;
     408                )
     409                ))
    378410IF_FEATURE_FIND_GROUP(  ACTS(group, gid_t gid;))
    379411IF_FEATURE_FIND_LINKS(  ACTS(links, char links_char; int links_count;))
     
    389421    smallint xdev_on;
    390422    recurse_flags_t recurse_flags;
     423    IF_FEATURE_FIND_EXEC_PLUS(unsigned max_argv_len;)
    391424} FIX_ALIASING;
    392 #define G (*(struct globals*)&bb_common_bufsiz1)
     425#define G (*(struct globals*)bb_common_bufsiz1)
    393426#define INIT_G() do { \
    394     struct G_sizecheck { \
    395         char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
    396     }; \
     427    setup_common_bufsiz(); \
     428    BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
    397429    /* we have to zero it out because of NOEXEC */ \
    398430    memset(&G, 0, sizeof(G)); \
    399431    IF_FEATURE_FIND_MAXDEPTH(G.minmaxdepth[1] = INT_MAX;) \
     432    IF_FEATURE_FIND_EXEC_PLUS(G.max_argv_len = bb_arg_max() - 2048;) \
    400433    G.need_print = 1; \
    401434    G.recurse_flags = ACTION_RECURSE; \
    402435} while (0)
    403 
    404 #if ENABLE_FEATURE_FIND_EXEC
    405 static unsigned count_subst(const char *str)
    406 {
    407     unsigned count = 0;
    408     while ((str = strstr(str, "{}")) != NULL) {
    409         count++;
    410         str++;
    411     }
    412     return count;
    413 }
    414 
    415 
    416 static char* subst(const char *src, unsigned count, const char* filename)
    417 {
    418     char *buf, *dst, *end;
    419     size_t flen = strlen(filename);
    420     /* we replace each '{}' with filename: growth by strlen-2 */
    421     buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1);
    422     while ((end = strstr(src, "{}"))) {
    423         memcpy(dst, src, end - src);
    424         dst += end - src;
    425         src = end + 2;
    426         memcpy(dst, filename, flen);
    427         dst += flen;
    428     }
    429     strcpy(dst, src);
    430     return buf;
    431 }
    432 #endif
    433436
    434437/* Return values of ACTFs ('action functions') are a bit mask:
     
    482485}
    483486
    484 
    485487#if !FNM_CASEFOLD
    486488static char *strcpy_upcase(char *dst, const char *src)
     
    557559ACTF(perm)
    558560{
    559     /* -perm +mode: at least one of perm_mask bits are set */
    560     if (ap->perm_char == '+')
     561    /* -perm [+/]mode: at least one of perm_mask bits are set */
     562    if (ap->perm_char == '+' || ap->perm_char == '/')
    561563        return (statbuf->st_mode & ap->perm_mask) != 0;
    562564    /* -perm -mode: all of perm_mask are set */
     
    606608#endif
    607609#if ENABLE_FEATURE_FIND_EXEC
    608 ACTF(exec)
     610static int do_exec(action_exec *ap, const char *fileName)
    609611{
    610612    int i, rc;
    611 #if ENABLE_USE_PORTABLE_CODE
    612     char **argv = alloca(sizeof(char*) * (ap->exec_argc + 1));
    613 #else /* gcc 4.3.1 generates smaller code: */
    614     char *argv[ap->exec_argc + 1];
    615 #endif
    616     for (i = 0; i < ap->exec_argc; i++)
    617         argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName);
    618     argv[i] = NULL; /* terminate the list */
     613# if ENABLE_FEATURE_FIND_EXEC_PLUS
     614    int size = ap->exec_argc + ap->filelist_idx + 1;
     615# else
     616    int size = ap->exec_argc + 1;
     617# endif
     618# if ENABLE_USE_PORTABLE_CODE
     619    char **argv = alloca(sizeof(char*) * size);
     620# else /* gcc 4.3.1 generates smaller code: */
     621    char *argv[size];
     622# endif
     623    char **pp = argv;
     624
     625    for (i = 0; i < ap->exec_argc; i++) {
     626        const char *arg = ap->exec_argv[i];
     627
     628# if ENABLE_FEATURE_FIND_EXEC_PLUS
     629        if (ap->filelist) {
     630            /* Handling "-exec +"
     631             * Only one exec_argv[i] has substitution in it.
     632             * Expand that one exec_argv[i] into file list.
     633             */
     634            if (ap->subst_count[i] == 0) {
     635                *pp++ = xstrdup(arg);
     636            } else {
     637                int j = 0;
     638                while (ap->filelist[j]) {
     639                    /* 2nd arg here should be ap->subst_count[i], but it is always 1: */
     640                    *pp++ = xmalloc_substitute_string(arg, 1, "{}", ap->filelist[j]);
     641                    free(ap->filelist[j]);
     642                    j++;
     643                }
     644            }
     645        } else
     646# endif
     647        {
     648            /* Handling "-exec ;" */
     649            *pp++ = xmalloc_substitute_string(arg, ap->subst_count[i], "{}", fileName);
     650        }
     651    }
     652    *pp = NULL; /* terminate the list */
     653
     654# if ENABLE_FEATURE_FIND_EXEC_PLUS
     655    if (ap->filelist) {
     656        ap->filelist[0] = NULL;
     657        ap->filelist_idx = 0;
     658        ap->file_len = 0;
     659    }
     660# endif
    619661
    620662    rc = spawn_and_wait(argv);
     
    627669    return rc == 0; /* return 1 if exitcode 0 */
    628670}
     671ACTF(exec)
     672{
     673# if ENABLE_FEATURE_FIND_EXEC_PLUS
     674    if (ap->filelist) {
     675        int rc;
     676
     677        ap->filelist = xrealloc_vector(ap->filelist, 8, ap->filelist_idx);
     678        ap->filelist[ap->filelist_idx++] = xstrdup(fileName);
     679        ap->file_len += strlen(fileName) + sizeof(char*) + 1;
     680        /* If we have lots of files already, exec the command */
     681        rc = 1;
     682        if (ap->file_len >= G.max_argv_len)
     683            rc = do_exec(ap, NULL);
     684        return rc;
     685    }
     686# endif
     687    return do_exec(ap, fileName);
     688}
     689# if ENABLE_FEATURE_FIND_EXEC_PLUS
     690static int flush_exec_plus(void)
     691{
     692    action *ap;
     693    action **app;
     694    action ***appp = G.actions;
     695    while ((app = *appp++) != NULL) {
     696        while ((ap = *app++) != NULL) {
     697            if (ap->f == (action_fp)func_exec) {
     698                action_exec *ae = (void*)ap;
     699                if (ae->filelist_idx != 0) {
     700                    int rc = do_exec(ae, NULL);
     701#  if ENABLE_FEATURE_FIND_NOT
     702                    if (ap->invert) rc = !rc;
     703#  endif
     704                    if (rc == 0)
     705                        return 1;
     706                }
     707            }
     708        }
     709    }
     710    return 0;
     711}
     712# endif
    629713#endif
    630714#if ENABLE_FEATURE_FIND_USER
     
    685769    int rc;
    686770    if (S_ISDIR(statbuf->st_mode)) {
    687         rc = rmdir(fileName);
     771        /* "find . -delete" skips rmdir(".") */
     772        rc = 0;
     773        if (NOT_LONE_CHAR(fileName, '.'))
     774            rc = rmdir(fileName);
    688775    } else {
    689776        rc = unlink(fileName);
     
    798885
    799886    if (mask == 0 || type[1] != '\0')
    800         bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
     887        bb_error_msg_and_die(bb_msg_invalid_arg_to, type, "-type");
    801888
    802889    return mask;
     
    812899        str++;
    813900    return str;
     901}
     902#endif
     903
     904/* Say no to GCCism */
     905#define USE_NESTED_FUNCTION 0
     906
     907#if !USE_NESTED_FUNCTION
     908struct pp_locals {
     909    action*** appp;
     910    unsigned cur_group;
     911    unsigned cur_action;
     912    IF_FEATURE_FIND_NOT( bool invert_flag; )
     913};
     914static action* alloc_action(struct pp_locals *ppl, int sizeof_struct, action_fp f)
     915{
     916    action *ap = xzalloc(sizeof_struct);
     917    action **app;
     918    action ***group = &ppl->appp[ppl->cur_group];
     919    *group = app = xrealloc(*group, (ppl->cur_action+2) * sizeof(ppl->appp[0][0]));
     920    app[ppl->cur_action++] = ap;
     921    app[ppl->cur_action] = NULL;
     922    ap->f = f;
     923    IF_FEATURE_FIND_NOT( ap->invert = ppl->invert_flag; )
     924    IF_FEATURE_FIND_NOT( ppl->invert_flag = 0; )
     925    return ap;
    814926}
    815927#endif
     
    9011013    ;
    9021014
     1015#if !USE_NESTED_FUNCTION
     1016    struct pp_locals ppl;
     1017#define appp        (ppl.appp       )
     1018#define cur_group   (ppl.cur_group  )
     1019#define cur_action  (ppl.cur_action )
     1020#define invert_flag (ppl.invert_flag)
     1021#define ALLOC_ACTION(name) (action_##name*)alloc_action(&ppl, sizeof(action_##name), (action_fp) func_##name)
     1022#else
    9031023    action*** appp;
    904     unsigned cur_group = 0;
    905     unsigned cur_action = 0;
    906     IF_FEATURE_FIND_NOT( bool invert_flag = 0; )
     1024    unsigned cur_group;
     1025    unsigned cur_action;
     1026    IF_FEATURE_FIND_NOT( bool invert_flag; )
    9071027
    9081028    /* This is the only place in busybox where we use nested function.
     
    9131033    {
    9141034        action *ap;
    915         appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(*appp));
     1035        appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(appp[0][0]));
    9161036        appp[cur_group][cur_action++] = ap = xzalloc(sizeof_struct);
    9171037        appp[cur_group][cur_action] = NULL;
     
    9211041        return ap;
    9221042    }
    923 
    9241043#define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name)
    925 
     1044#endif
     1045
     1046    cur_group = 0;
     1047    cur_action = 0;
     1048    IF_FEATURE_FIND_NOT( invert_flag = 0; )
    9261049    appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */
    9271050
     
    9491072        /* Options */
    9501073        if (parm == OPT_FOLLOW) {
    951                         dbg("follow enabled: %d", __LINE__);
    952                         G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
     1074            dbg("follow enabled: %d", __LINE__);
     1075            G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
    9531076        }
    9541077#if ENABLE_FEATURE_FIND_XDEV
     
    9881111            /* start new OR group */
    9891112            cur_group++;
    990             appp = xrealloc(appp, (cur_group+2) * sizeof(*appp));
     1113            appp = xrealloc(appp, (cur_group+2) * sizeof(appp[0]));
    9911114            /*appp[cur_group] = NULL; - already NULL */
    9921115            appp[cur_group+1] = NULL;
     
    10311154            int i;
    10321155            action_exec *ap;
     1156            IF_FEATURE_FIND_EXEC_PLUS(int all_subst = 0;)
    10331157            dbg("%d", __LINE__);
    10341158            G.need_print = 0;
     
    10431167                // find -exec echo Foo ">{}<" "+"
    10441168                // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...".
    1045                 // TODO (so far we treat "+" just like ";")
    10461169                if ((argv[0][0] == ';' || argv[0][0] == '+')
    10471170                 && argv[0][1] == '\0'
    10481171                ) {
     1172# if ENABLE_FEATURE_FIND_EXEC_PLUS
     1173                    if (argv[0][0] == '+')
     1174                        ap->filelist = xzalloc(sizeof(ap->filelist[0]));
     1175# endif
    10491176                    break;
    10501177                }
     
    10561183            ap->subst_count = xmalloc(ap->exec_argc * sizeof(int));
    10571184            i = ap->exec_argc;
    1058             while (i--)
    1059                 ap->subst_count[i] = count_subst(ap->exec_argv[i]);
     1185            while (i--) {
     1186                ap->subst_count[i] = count_strstr(ap->exec_argv[i], "{}");
     1187                IF_FEATURE_FIND_EXEC_PLUS(all_subst += ap->subst_count[i];)
     1188            }
     1189# if ENABLE_FEATURE_FIND_EXEC_PLUS
     1190            /*
     1191             * coreutils expects {} to appear only once in "-exec +"
     1192             */
     1193            if (all_subst != 1 && ap->filelist)
     1194                bb_error_msg_and_die("only one '{}' allowed for -exec +");
     1195# endif
    10601196        }
    10611197#endif
     
    11201256 *              Symbolic modes use mode 0 as a point of departure.
    11211257 * -perm -BITS  All of the BITS are set in file's mode.
    1122  * -perm +BITS  At least one of the BITS is set in file's mode.
     1258 * -perm [+/]BITS  At least one of the BITS is set in file's mode.
    11231259 */
    11241260        else if (parm == PARM_perm) {
     
    11271263            ap = ALLOC_ACTION(perm);
    11281264            ap->perm_char = arg1[0];
    1129             arg1 = plus_minus_num(arg1);
     1265            arg1 = (arg1[0] == '/' ? arg1+1 : plus_minus_num(arg1));
    11301266            /*ap->perm_mask = 0; - ALLOC_ACTION did it */
    1131             if (!bb_parse_mode(arg1, &ap->perm_mask))
     1267            ap->perm_mask = bb_parse_mode(arg1, ap->perm_mask);
     1268            if (ap->perm_mask == (mode_t)-1)
    11321269                bb_error_msg_and_die("invalid mode '%s'", arg1);
    11331270        }
     
    12461383    return appp;
    12471384#undef ALLOC_ACTION
     1385#undef appp
     1386#undef cur_action
     1387#undef invert_flag
    12481388}
    12491389
     
    12521392{
    12531393    int i, firstopt, status = EXIT_SUCCESS;
     1394    char **past_HLP, *saved;
    12541395
    12551396    INIT_G();
    12561397
    1257     argv++;
     1398    /* "find -type f" + getopt("+HLP") => disaster.
     1399     * Need to avoid getopt running into a non-HLP option.
     1400     * Do this by temporarily storing NULL there:
     1401     */
     1402    past_HLP = argv;
     1403    for (;;) {
     1404        saved = *++past_HLP;
     1405        if (!saved)
     1406            break;
     1407        if (saved[0] != '-')
     1408            break;
     1409        if (!saved[1])
     1410            break; /* it is "-" */
     1411        if ((saved+1)[strspn(saved+1, "HLP")] != '\0')
     1412            break;
     1413    }
     1414    *past_HLP = NULL;
     1415    /* "+": stop on first non-option */
     1416    i = getopt32(argv, "+HLP");
     1417    if (i & (1<<0))
     1418        G.recurse_flags |= ACTION_FOLLOWLINKS_L0 | ACTION_DANGLING_OK;
     1419    if (i & (1<<1))
     1420        G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
     1421    /* -P is default and is ignored */
     1422    argv = past_HLP; /* same result as "argv += optind;" */
     1423    *past_HLP = saved;
     1424
    12581425    for (firstopt = 0; argv[firstopt]; firstopt++) {
    12591426        if (argv[firstopt][0] == '-')
     
    12981465                0)              /* depth */
    12991466        ) {
    1300             status = EXIT_FAILURE;
    1301         }
    1302     }
    1303 
     1467            status |= EXIT_FAILURE;
     1468        }
     1469    }
     1470
     1471    IF_FEATURE_FIND_EXEC_PLUS(status |= flush_exec_plus();)
    13041472    return status;
    13051473}
  • branches/3.3/mindi-busybox/findutils/grep.c

    r3232 r3621  
    5959
    6060#include "libbb.h"
     61#include "common_bufsiz.h"
    6162#include "xregex.h"
    6263
     
    202203    const char *cur_file;    /* the current file we are reading */
    203204} FIX_ALIASING;
    204 #define G (*(struct globals*)&bb_common_bufsiz1)
     205#define G (*(struct globals*)bb_common_bufsiz1)
    205206#define INIT_G() do { \
    206     struct G_sizecheck { \
    207         char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
    208     }; \
     207    setup_common_bufsiz(); \
     208    BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
    209209} while (0)
    210210#define max_matches       (G.max_matches         )
     
    374374                }
    375375            } else {
     376#if ENABLE_EXTRA_COMPAT
     377                unsigned start_pos;
     378#else
     379                int match_flg;
     380#endif
     381                char *match_at;
     382
    376383                if (!(gl->flg_mem_alocated_compiled & COMPILED)) {
    377384                    gl->flg_mem_alocated_compiled |= COMPILED;
     
    388395                gl->matched_range.rm_so = 0;
    389396                gl->matched_range.rm_eo = 0;
    390 #endif
     397                match_flg = 0;
     398#else
     399                start_pos = 0;
     400#endif
     401                match_at = line;
     402 opt_w_again:
     403//bb_error_msg("'%s' start_pos:%d line_len:%d", match_at, start_pos, line_len);
    391404                if (
    392405#if !ENABLE_EXTRA_COMPAT
    393                     regexec(&gl->compiled_regex, line, 1, &gl->matched_range, 0) == 0
    394 #else
    395                     re_search(&gl->compiled_regex, line, line_len,
    396                             /*start:*/ 0, /*range:*/ line_len,
     406                    regexec(&gl->compiled_regex, match_at, 1, &gl->matched_range, match_flg) == 0
     407#else
     408                    re_search(&gl->compiled_regex, match_at, line_len,
     409                            start_pos, /*range:*/ line_len,
    397410                            &gl->matched_range) >= 0
    398411#endif
     
    400413                    if (option_mask32 & OPT_x) {
    401414                        found = (gl->matched_range.rm_so == 0
    402                                  && line[gl->matched_range.rm_eo] == '\0');
     415                                 && match_at[gl->matched_range.rm_eo] == '\0');
    403416                    } else
    404417                    if (!(option_mask32 & OPT_w)) {
     
    406419                    } else {
    407420                        char c = ' ';
    408                         if (gl->matched_range.rm_so)
    409                             c = line[gl->matched_range.rm_so - 1];
     421                        if (match_at > line || gl->matched_range.rm_so != 0) {
     422                            c = match_at[gl->matched_range.rm_so - 1];
     423                        }
    410424                        if (!isalnum(c) && c != '_') {
    411                             c = line[gl->matched_range.rm_eo];
    412                             if (!c || (!isalnum(c) && c != '_'))
    413                                 found = 1;
     425                            c = match_at[gl->matched_range.rm_eo];
    414426                        }
    415 //BUG: "echo foop foo | grep -w foo" should match, but doesn't:
    416 //we bail out on first "mismatch" because it's not a word.
     427                        if (!isalnum(c) && c != '_') {
     428                            found = 1;
     429                        } else {
     430            /*
     431             * Why check gl->matched_range.rm_eo?
     432             * Zero-length match makes -w skip the line:
     433             * "echo foo | grep ^" prints "foo",
     434             * "echo foo | grep -w ^" prints nothing.
     435             * Without such check, we can loop forever.
     436             */
     437#if !ENABLE_EXTRA_COMPAT
     438                            if (gl->matched_range.rm_eo != 0) {
     439                                match_at += gl->matched_range.rm_eo;
     440                                match_flg |= REG_NOTBOL;
     441                                goto opt_w_again;
     442                            }
     443#else
     444                            if (gl->matched_range.rm_eo > start_pos) {
     445                                start_pos = gl->matched_range.rm_eo;
     446                                goto opt_w_again;
     447                            }
     448#endif
     449                        }
    417450                    }
    418451                }
     
    636669    recursive_action(dir,
    637670        /* recurse=yes */ ACTION_RECURSE |
    638         /* followLinks=no */
     671        /* followLinks=command line only */ ACTION_FOLLOWLINKS_L0 |
    639672        /* depthFirst=yes */ ACTION_DEPTHFIRST,
    640673        /* fileAction= */ file_action_grep,
     
    651684    int matched;
    652685    llist_t *fopt = NULL;
     686#if ENABLE_FEATURE_GREP_CONTEXT
     687    int Copt, opts;
     688#endif
     689    INIT_G();
     690
     691    /* For grep, exitcode of 1 is "not found". Other errors are 2: */
     692    xfunc_error_retval = 2;
    653693
    654694    /* do normal option parsing */
    655695#if ENABLE_FEATURE_GREP_CONTEXT
    656     int Copt, opts;
    657 
    658696    /* -H unsets -h; -C unsets -A,-B; -e,-f are lists;
    659697     * -m,-A,-B,-C have numeric param */
     
    711749
    712750#if !ENABLE_EXTRA_COMPAT
    713     if (!(option_mask32 & (OPT_o | OPT_w)))
     751    if (!(option_mask32 & (OPT_o | OPT_w | OPT_x)))
    714752        reflags = REG_NOSUB;
    715753#endif
  • branches/3.3/mindi-busybox/findutils/xargs.c

    r3232 r3621  
    5454//config:     instead of whitespace, and the quotes and backslash
    5555//config:     are not special.
     56//config:
     57//config:config FEATURE_XARGS_SUPPORT_REPL_STR
     58//config:   bool "Enable -I STR: string to replace"
     59//config:   default y
     60//config:   depends on XARGS
     61//config:   help
     62//config:     Support -I STR and -i[STR] options.
    5663
    5764//applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, BB_DIR_USR_BIN, BB_SUID_DROP, xargs))
     
    6067
    6168#include "libbb.h"
     69#include "common_bufsiz.h"
    6270
    6371/* This is a NOEXEC applet. Be very careful! */
     
    8694struct globals {
    8795    char **args;
     96#if ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR
     97    char **argv;
     98    const char *repl_str;
     99    char eol_ch;
     100#endif
    88101    const char *eof_str;
    89102    int idx;
    90103} FIX_ALIASING;
    91 #define G (*(struct globals*)&bb_common_bufsiz1)
     104#define G (*(struct globals*)bb_common_bufsiz1)
    92105#define INIT_G() do { \
     106    setup_common_bufsiz(); \
    93107    G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \
     108    IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \
     109    IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \
    94110} while (0)
    95111
    96112
    97 /*
    98  * This function has special algorithm.
    99  * Don't use fork and include to main!
    100  */
    101113static int xargs_exec(void)
    102114{
     
    113125    }
    114126    if (status >= 0x180) {
    115         bb_error_msg("%s: terminated by signal %d",
     127        bb_error_msg("'%s' terminated by signal %d",
    116128            G.args[0], status - 0x180);
    117129        return 125;
     
    142154 * If reading discovers that last chars do not form the complete
    143155 * parameter, the pointer to the first such "tail character" is returned.
    144  * (buf has extra byte at the end to accomodate terminating NUL
     156 * (buf has extra byte at the end to accommodate terminating NUL
    145157 * of "tail characters" string).
    146158 * Otherwise, the returned pointer points to NUL byte.
     
    302314        }
    303315        *p++ = c;
    304         if (c == '\0') {   /* word's delimiter or EOF detected */
     316        if (c == '\0') {   /* NUL or EOF detected */
    305317            /* A full word is loaded */
    306318            store_param(s);
     
    324336#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
    325337
     338#if ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR
     339/*
     340 * Used if -I<repl> was specified.
     341 * In this mode, words aren't appended to PROG ARGS.
     342 * Instead, entire input line is read, then <repl> string
     343 * in every PROG and ARG is replaced with the line:
     344 *  echo -e "ho ho\nhi" | xargs -I_ cmd __ _
     345 * results in "cmd 'ho hoho ho' 'ho ho'"; "cmd 'hihi' 'hi'".
     346 * -n MAX_ARGS seems to be ignored.
     347 * Tested with GNU findutils 4.5.10.
     348 */
     349//FIXME: n_max_chars is not handled the same way as in GNU findutils.
     350//FIXME: quoting is not implemented.
     351static char* FAST_FUNC process_stdin_with_replace(int n_max_chars, int n_max_arg UNUSED_PARAM, char *buf)
     352{
     353    int i;
     354    char *end, *p;
     355
     356    /* Free strings from last invocation, if any */
     357    for (i = 0; G.args && G.args[i]; i++)
     358        if (G.args[i] != G.argv[i])
     359            free(G.args[i]);
     360
     361    end = buf + n_max_chars;
     362    p = buf;
     363
     364    while (1) {
     365        int c = getchar();
     366        if (c == EOF || c == G.eol_ch) {
     367            if (p == buf)
     368                goto ret; /* empty line */
     369            c = '\0';
     370        }
     371        *p++ = c;
     372        if (c == '\0') {   /* EOL or EOF detected */
     373            i = 0;
     374            while (G.argv[i]) {
     375                char *arg = G.argv[i];
     376                int count = count_strstr(arg, G.repl_str);
     377                if (count != 0)
     378                    arg = xmalloc_substitute_string(arg, count, G.repl_str, buf);
     379                store_param(arg);
     380                dbg_msg("args[]:'%s'", arg);
     381                i++;
     382            }
     383            p = buf;
     384            goto ret;
     385        }
     386        if (p == end) {
     387            goto ret;
     388        }
     389    }
     390 ret:
     391    *p = '\0';
     392    /* store_param(NULL) - caller will do it */
     393    dbg_msg("return:'%s'", buf);
     394    return buf;
     395}
     396#endif
     397
    326398#if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
    327399/* Prompt the user for a response, and
    328    if the user responds affirmatively, return true;
    329    otherwise, return false. Uses "/dev/tty", not stdin. */
     400 * if user responds affirmatively, return true;
     401 * otherwise, return false. Uses "/dev/tty", not stdin.
     402 */
    330403static int xargs_ask_confirmation(void)
    331404{
     
    361434//usage:     "\n    -n N    Pass no more than N args to PROG"
    362435//usage:     "\n    -s N    Pass command line of no more than N bytes"
     436//usage:    IF_FEATURE_XARGS_SUPPORT_REPL_STR(
     437//usage:     "\n    -I STR  Replace STR within PROG ARGS with input line"
     438//usage:    )
    363439//usage:    IF_FEATURE_XARGS_SUPPORT_TERMOPT(
    364440//usage:     "\n    -x  Exit if size is exceeded"
     
    379455    IF_FEATURE_XARGS_SUPPORT_TERMOPT(     OPTBIT_TERMINATE  ,)
    380456    IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   OPTBIT_ZEROTERM   ,)
     457    IF_FEATURE_XARGS_SUPPORT_REPL_STR(    OPTBIT_REPLSTR    ,)
     458    IF_FEATURE_XARGS_SUPPORT_REPL_STR(    OPTBIT_REPLSTR1   ,)
    381459
    382460    OPT_VERBOSE     = 1 << OPTBIT_VERBOSE    ,
     
    389467    OPT_TERMINATE   = IF_FEATURE_XARGS_SUPPORT_TERMOPT(     (1 << OPTBIT_TERMINATE  )) + 0,
    390468    OPT_ZEROTERM    = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   (1 << OPTBIT_ZEROTERM   )) + 0,
     469    OPT_REPLSTR     = IF_FEATURE_XARGS_SUPPORT_REPL_STR(    (1 << OPTBIT_REPLSTR    )) + 0,
     470    OPT_REPLSTR1    = IF_FEATURE_XARGS_SUPPORT_REPL_STR(    (1 << OPTBIT_REPLSTR1   )) + 0,
    391471};
    392472#define OPTION_STR "+trn:s:e::E:" \
    393473    IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
    394474    IF_FEATURE_XARGS_SUPPORT_TERMOPT(     "x") \
    395     IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   "0")
     475    IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   "0") \
     476    IF_FEATURE_XARGS_SUPPORT_REPL_STR(    "I:i::")
    396477
    397478int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     
    406487    int n_max_chars;
    407488    int n_max_arg;
    408 #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
     489#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM \
     490 || ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR
    409491    char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin;
    410492#else
     
    420502        ;
    421503#endif
    422     opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str);
     504    opt = getopt32(argv, OPTION_STR,
     505        &max_args, &max_chars, &G.eof_str, &G.eof_str
     506        IF_FEATURE_XARGS_SUPPORT_REPL_STR(, &G.repl_str, &G.repl_str)
     507    );
    423508
    424509    /* -E ""? You may wonder why not just omit -E?
     
    428513        G.eof_str = NULL;
    429514
    430     if (opt & OPT_ZEROTERM)
    431         IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
     515    if (opt & OPT_ZEROTERM) {
     516        IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin;)
     517        IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\0';)
     518    }
    432519
    433520    argv += optind;
     
    439526    }
    440527
    441     /* -s NUM default. fileutils-4.4.2 uses 128k, but I heasitate
    442      * to use such a big value - first need to change code to use
    443      * growable buffer instead of fixed one.
    444      */
    445     n_max_chars = 32 * 1024;
    446     /* Make smaller if system does not allow our default value.
     528    /*
    447529     * The Open Group Base Specifications Issue 6:
    448530     * "The xargs utility shall limit the command line length such that
     
    452534     * shall not exceed {ARG_MAX}-2048 bytes".
    453535     */
    454     {
    455         long arg_max = 0;
    456 #if defined _SC_ARG_MAX
    457         arg_max = sysconf(_SC_ARG_MAX) - 2048;
    458 #elif defined ARG_MAX
    459         arg_max = ARG_MAX - 2048;
    460 #endif
    461         if (arg_max > 0 && n_max_chars > arg_max)
    462             n_max_chars = arg_max;
    463     }
     536    n_max_chars = bb_arg_max();
     537    if (n_max_chars > 32 * 1024)
     538        n_max_chars = 32 * 1024;
     539    /*
     540     * POSIX suggests substracting 2048 bytes from sysconf(_SC_ARG_MAX)
     541     * so that the process may safely modify its environment.
     542     */
     543    n_max_chars -= 2048;
     544
    464545    if (opt & OPT_UPTO_SIZE) {
    465546        n_max_chars = xatou_range(max_chars, 1, INT_MAX);
     
    487568    }
    488569
    489     /* Allocate pointers for execvp */
    490     /* We can statically allocate (argc + n_max_arg + 1) elements
    491      * and do not bother with resizing args[], but on 64-bit machines
    492      * this results in args[] vector which is ~8 times bigger
    493      * than n_max_chars! That is, with n_max_chars == 20k,
    494      * args[] will take 160k (!), which will most likely be
    495      * almost entirely unused.
    496      */
    497     /* See store_param() for matching 256-step growth logic */
    498     G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff));
    499 
    500     /* Store the command to be executed, part 1 */
    501     for (i = 0; argv[i]; i++)
    502         G.args[i] = argv[i];
     570#if ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR
     571    if (opt & (OPT_REPLSTR | OPT_REPLSTR1)) {
     572        /*
     573         * -I<str>:
     574         * Unmodified args are kept in G.argv[i],
     575         * G.args[i] receives malloced G.argv[i] with <str> replaced
     576         * with input line. Setting this up:
     577         */
     578        G.args = NULL;
     579        G.argv = argv;
     580        argc = 0;
     581        read_args = process_stdin_with_replace;
     582        /* Make -I imply -r. GNU findutils seems to do the same: */
     583        /* (otherwise "echo -n | xargs -I% echo %" would SEGV) */
     584        opt |= OPT_NO_EMPTY;
     585    } else
     586#endif
     587    {
     588        /* Allocate pointers for execvp.
     589         * We can statically allocate (argc + n_max_arg + 1) elements
     590         * and do not bother with resizing args[], but on 64-bit machines
     591         * this results in args[] vector which is ~8 times bigger
     592         * than n_max_chars! That is, with n_max_chars == 20k,
     593         * args[] will take 160k (!), which will most likely be
     594         * almost entirely unused.
     595         *
     596         * See store_param() for matching 256-step growth logic
     597         */
     598        G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff));
     599        /* Store the command to be executed, part 1 */
     600        for (i = 0; argv[i]; i++)
     601            G.args[i] = argv[i];
     602    }
    503603
    504604    while (1) {
Note: See TracChangeset for help on using the changeset viewer.