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


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:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • 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.