Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/findutils/xargs.c

    r1765 r2725  
    22/*
    33 * Mini xargs implementation for busybox
    4  * Options are supported: "-prtx -n max_arg -s max_chars -e[ouf_str]"
    54 *
    65 * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru>
     
    1110 * and David MacKenzie <djm@gnu.ai.mit.edu>.
    1211 *
    13  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     12 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1413 *
    1514 * xargs is described in the Single Unix Specification v3 at
    1615 * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html
    17  *
    1816 */
    1917
     18//applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, _BB_DIR_USR_BIN, _BB_SUID_DROP, xargs))
     19
     20//kbuild:lib-$(CONFIG_XARGS) += xargs.o
     21
     22//config:config XARGS
     23//config:   bool "xargs"
     24//config:   default y
     25//config:   help
     26//config:     xargs is used to execute a specified command for
     27//config:     every item from standard input.
     28//config:
     29//config:config FEATURE_XARGS_SUPPORT_CONFIRMATION
     30//config:   bool "Enable -p: prompt and confirmation"
     31//config:   default y
     32//config:   depends on XARGS
     33//config:   help
     34//config:     Support -p: prompt the user whether to run each command
     35//config:     line and read a line from the terminal.
     36//config:
     37//config:config FEATURE_XARGS_SUPPORT_QUOTES
     38//config:   bool "Enable single and double quotes and backslash"
     39//config:   default y
     40//config:   depends on XARGS
     41//config:   help
     42//config:     Support quoting in the input.
     43//config:
     44//config:config FEATURE_XARGS_SUPPORT_TERMOPT
     45//config:   bool "Enable -x: exit if -s or -n is exceeded"
     46//config:   default y
     47//config:   depends on XARGS
     48//config:   help
     49//config:     Support -x: exit if the command size (see the -s or -n option)
     50//config:     is exceeded.
     51//config:
     52//config:config FEATURE_XARGS_SUPPORT_ZERO_TERM
     53//config:   bool "Enable -0: NUL-terminated input"
     54//config:   default y
     55//config:   depends on XARGS
     56//config:   help
     57//config:     Support -0: input items are terminated by a NUL character
     58//config:     instead of whitespace, and the quotes and backslash
     59//config:     are not special.
     60
    2061#include "libbb.h"
    2162
     
    2364
    2465
    25 /* COMPAT:  SYSV version defaults size (and has a max value of) to 470.
    26    We try to make it as large as possible. */
    27 #if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
    28 #define ARG_MAX sysconf (_SC_ARG_MAX)
    29 #endif
    30 #ifndef ARG_MAX
    31 #define ARG_MAX 470
    32 #endif
     66//#define dbg_msg(...) bb_error_msg(__VA_ARGS__)
     67#define dbg_msg(...) ((void)0)
    3368
    3469
     
    4883#endif
    4984
     85
     86struct globals {
     87    char **args;
     88    const char *eof_str;
     89    int idx;
     90} FIX_ALIASING;
     91#define G (*(struct globals*)&bb_common_bufsiz1)
     92#define INIT_G() do { } while (0)
     93
     94
    5095/*
    51    This function has special algorithm.
    52    Don't use fork and include to main!
    53 */
    54 static int xargs_exec(char **args)
     96 * This function has special algorithm.
     97 * Don't use fork and include to main!
     98 */
     99static int xargs_exec(void)
    55100{
    56101    int status;
    57102
    58     status = spawn_and_wait(args);
     103    status = spawn_and_wait(G.args);
    59104    if (status < 0) {
    60         bb_perror_msg("%s", args[0]);
     105        bb_simple_perror_msg(G.args[0]);
    61106        return errno == ENOENT ? 127 : 126;
    62107    }
    63108    if (status == 255) {
    64         bb_error_msg("%s: exited with status 255; aborting", args[0]);
     109        bb_error_msg("%s: exited with status 255; aborting", G.args[0]);
    65110        return 124;
    66111    }
    67 /* Huh? I think we won't see this, ever. We don't wait with WUNTRACED!
    68     if (WIFSTOPPED(status)) {
    69         bb_error_msg("%s: stopped by signal %d",
    70             args[0], WSTOPSIG(status));
    71         return 125;
    72     }
    73 */
    74     if (status >= 1000) {
     112    if (status >= 0x180) {
    75113        bb_error_msg("%s: terminated by signal %d",
    76             args[0], status - 1000);
     114            G.args[0], status - 0x180);
    77115        return 125;
    78116    }
     
    82120}
    83121
    84 
    85 typedef struct xlist_t {
    86     struct xlist_t *link;
    87     size_t length;
    88     char xstr[1];
    89 } xlist_t;
    90 
    91 static smallint eof_stdin_detected;
    92 
    93 #define ISBLANK(c) ((c) == ' ' || (c) == '\t')
    94 #define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \
    95             || (c) == '\f' || (c) == '\v')
     122/* In POSIX/C locale isspace is only these chars: "\t\n\v\f\r" and space.
     123 * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13.
     124 */
     125#define ISSPACE(a) ({ unsigned char xargs__isspace = (a) - 9; xargs__isspace == (' ' - 9) || xargs__isspace <= (13 - 9); })
     126
     127static void store_param(char *s)
     128{
     129    /* Grow by 256 elements at once */
     130    if (!(G.idx & 0xff)) { /* G.idx == N*256 */
     131        /* Enlarge, make G.args[(N+1)*256 - 1] last valid idx */
     132        G.args = xrealloc(G.args, sizeof(G.args[0]) * (G.idx + 0x100));
     133    }
     134    G.args[G.idx++] = s;
     135}
     136
     137/* process[0]_stdin:
     138 * Read characters into buf[n_max_chars+1], and when parameter delimiter
     139 * is seen, store the address of a new parameter to args[].
     140 * If reading discovers that last chars do not form the complete
     141 * parameter, the pointer to the first such "tail character" is returned.
     142 * (buf has extra byte at the end to accomodate terminating NUL
     143 * of "tail characters" string).
     144 * Otherwise, the returned pointer points to NUL byte.
     145 * On entry, buf[] may contain some "seed chars" which are to become
     146 * the beginning of the first parameter.
     147 */
    96148
    97149#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
    98 static xlist_t *process_stdin(xlist_t *list_arg,
    99     const char *eof_str, size_t mc, char *buf)
     150static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
    100151{
    101152#define NORM      0
     
    103154#define BACKSLASH 2
    104155#define SPACE     4
    105 
    106     char *s = NULL;         /* start word */
    107     char *p = NULL;         /* pointer to end word */
    108     char q = '\0';          /* quote char */
     156    char q = '\0';             /* quote char */
    109157    char state = NORM;
    110     char eof_str_detected = 0;
    111     size_t line_l = 0;      /* size loaded args line */
    112     int c;                  /* current char */
    113     xlist_t *cur;
    114     xlist_t *prev;
    115 
    116     prev = cur = list_arg;
     158    char *s = buf;             /* start of the word */
     159    char *p = s + strlen(buf); /* end of the word */
     160
     161    buf += n_max_chars;        /* past buffer's end */
     162
     163    /* "goto ret" is used instead of "break" to make control flow
     164     * more obvious: */
     165
    117166    while (1) {
    118         if (!cur) break;
    119         prev = cur;
    120         line_l += cur->length;
    121         cur = cur->link;
    122     }
    123 
    124     while (!eof_stdin_detected) {
    125         c = getchar();
     167        int c = getchar();
    126168        if (c == EOF) {
    127             eof_stdin_detected = 1;
    128             if (s)
    129                 goto unexpected_eof;
    130             break;
    131         }
    132         if (eof_str_detected)
    133             continue;
     169            if (p != s)
     170                goto close_word;
     171            goto ret;
     172        }
    134173        if (state == BACKSLASH) {
    135174            state = NORM;
    136175            goto set;
    137         } else if (state == QUOTE) {
     176        }
     177        if (state == QUOTE) {
    138178            if (c != q)
    139179                goto set;
     
    142182        } else { /* if (state == NORM) */
    143183            if (ISSPACE(c)) {
    144                 if (s) {
    145  unexpected_eof:
     184                if (p != s) {
     185 close_word:
    146186                    state = SPACE;
    147187                    c = '\0';
     
    149189                }
    150190            } else {
    151                 if (s == NULL)
    152                     s = p = buf;
    153191                if (c == '\\') {
    154192                    state = BACKSLASH;
     
    158196                } else {
    159197 set:
    160                     if ((size_t)(p - buf) >= mc)
    161                         bb_error_msg_and_die("argument line too long");
    162198                    *p++ = c;
    163199                }
     
    169205                    q == '\'' ? "single" : "double");
    170206            }
    171             /* word loaded */
    172             if (eof_str) {
    173                 eof_str_detected = (strcmp(s, eof_str) == 0);
    174             }
    175             if (!eof_str_detected) {
    176                 size_t length = (p - buf);
    177                 /* Dont xzalloc - it can be quite big */
    178                 cur = xmalloc(offsetof(xlist_t, xstr) + length);
    179                 cur->link = NULL;
    180                 cur->length = length;
    181                 memcpy(cur->xstr, s, length);
    182                 if (prev == NULL) {
    183                     list_arg = cur;
    184                 } else {
    185                     prev->link = cur;
     207            /* A full word is loaded */
     208            if (G.eof_str) {
     209                if (strcmp(s, G.eof_str) == 0) {
     210                    while (getchar() != EOF)
     211                        continue;
     212                    p = s;
     213                    goto ret;
    186214                }
    187                 prev = cur;
    188                 line_l += length;
    189                 if (line_l > mc) {
    190                     /* stop memory usage :-) */
    191                     break;
    192                 }
    193             }
    194             s = NULL;
     215            }
     216            store_param(s);
     217            dbg_msg("args[]:'%s'", s);
     218            s = p;
     219            n_max_arg--;
     220            if (n_max_arg == 0) {
     221                goto ret;
     222            }
    195223            state = NORM;
    196224        }
    197     }
    198     return list_arg;
     225        if (p == buf) {
     226            goto ret;
     227        }
     228    }
     229 ret:
     230    *p = '\0';
     231    /* store_param(NULL) - caller will do it */
     232    dbg_msg("return:'%s'", s);
     233    return s;
    199234}
    200235#else
    201236/* The variant does not support single quotes, double quotes or backslash */
    202 static xlist_t *process_stdin(xlist_t *list_arg,
    203         const char *eof_str, size_t mc, char *buf)
    204 {
    205 
    206     int c;                  /* current char */
    207     char eof_str_detected = 0;
    208     char *s = NULL;         /* start word */
    209     char *p = NULL;         /* pointer to end word */
    210     size_t line_l = 0;      /* size loaded args line */
    211     xlist_t *cur;
    212     xlist_t *prev;
    213 
    214     prev = cur = list_arg;
     237static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
     238{
     239    char *s = buf;             /* start of the word */
     240    char *p = s + strlen(buf); /* end of the word */
     241
     242    buf += n_max_chars;        /* past buffer's end */
     243
    215244    while (1) {
    216         if (!cur) break;
    217         prev = cur;
    218         line_l += cur->length;
    219         cur = cur->link;
    220     }
    221 
    222     while (!eof_stdin_detected) {
    223         c = getchar();
     245        int c = getchar();
    224246        if (c == EOF) {
    225             eof_stdin_detected = 1;
    226         }
    227         if (eof_str_detected)
    228             continue;
     247            if (p == s)
     248                goto ret;
     249        }
    229250        if (c == EOF || ISSPACE(c)) {
    230             if (s == NULL)
     251            if (p == s)
    231252                continue;
    232253            c = EOF;
    233254        }
    234         if (s == NULL)
    235             s = p = buf;
    236         if ((p - buf) >= mc)
    237             bb_error_msg_and_die("argument line too long");
    238255        *p++ = (c == EOF ? '\0' : c);
    239256        if (c == EOF) { /* word's delimiter or EOF detected */
    240             /* word loaded */
    241             if (eof_str) {
    242                 eof_str_detected = (strcmp(s, eof_str) == 0);
    243             }
    244             if (!eof_str_detected) {
    245                 size_t length = (p - buf);
    246                 /* Dont xzalloc - it can be quite big */
    247                 cur = xmalloc(offsetof(xlist_t, xstr) + length);
    248                 cur->link = NULL;
    249                 cur->length = length;
    250                 memcpy(cur->xstr, s, length);
    251                 if (prev == NULL) {
    252                     list_arg = cur;
    253                 } else {
    254                     prev->link = cur;
     257            /* A full word is loaded */
     258            if (G.eof_str) {
     259                if (strcmp(s, G.eof_str) == 0) {
     260                    while (getchar() != EOF)
     261                        continue;
     262                    p = s;
     263                    goto ret;
    255264                }
    256                 prev = cur;
    257                 line_l += length;
    258                 if (line_l > mc) {
    259                     /* stop memory usage :-) */
    260                     break;
    261                 }
    262                 s = NULL;
    263             }
    264         }
    265     }
    266     return list_arg;
     265            }
     266            store_param(s);
     267            dbg_msg("args[]:'%s'", s);
     268            s = p;
     269            n_max_arg--;
     270            if (n_max_arg == 0) {
     271                goto ret;
     272            }
     273        }
     274        if (p == buf) {
     275            goto ret;
     276        }
     277    }
     278 ret:
     279    *p = '\0';
     280    /* store_param(NULL) - caller will do it */
     281    dbg_msg("return:'%s'", s);
     282    return s;
    267283}
    268284#endif /* FEATURE_XARGS_SUPPORT_QUOTES */
    269285
     286#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
     287static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf)
     288{
     289    char *s = buf;             /* start of the word */
     290    char *p = s + strlen(buf); /* end of the word */
     291
     292    buf += n_max_chars;        /* past buffer's end */
     293
     294    while (1) {
     295        int c = getchar();
     296        if (c == EOF) {
     297            if (p == s)
     298                goto ret;
     299            c = '\0';
     300        }
     301        *p++ = c;
     302        if (c == '\0') {   /* word's delimiter or EOF detected */
     303            /* A full word is loaded */
     304            store_param(s);
     305            dbg_msg("args[]:'%s'", s);
     306            s = p;
     307            n_max_arg--;
     308            if (n_max_arg == 0) {
     309                goto ret;
     310            }
     311        }
     312        if (p == buf) {
     313            goto ret;
     314        }
     315    }
     316 ret:
     317    *p = '\0';
     318    /* store_param(NULL) - caller will do it */
     319    dbg_msg("return:'%s'", s);
     320    return s;
     321}
     322#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
    270323
    271324#if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
     
    278331    int c, savec;
    279332
    280     tty_stream = xfopen(CURRENT_TTY, "r");
     333    tty_stream = xfopen_for_read(CURRENT_TTY);
    281334    fputs(" ?...", stderr);
    282     fflush(stderr);
     335    fflush_all();
    283336    c = savec = getc(tty_stream);
    284337    while (c != EOF && c != '\n')
     
    289342#else
    290343# define xargs_ask_confirmation() 1
    291 #endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */
    292 
    293 #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
    294 static xlist_t *process0_stdin(xlist_t *list_arg,
    295         const char *eof_str ATTRIBUTE_UNUSED, size_t mc, char *buf)
    296 {
    297     int c;                  /* current char */
    298     char *s = NULL;         /* start word */
    299     char *p = NULL;         /* pointer to end word */
    300     size_t line_l = 0;      /* size loaded args line */
    301     xlist_t *cur;
    302     xlist_t *prev;
    303 
    304     prev = cur = list_arg;
    305     while (1) {
    306         if (!cur) break;
    307         prev = cur;
    308         line_l += cur->length;
    309         cur = cur->link;
    310     }
    311 
    312     while (!eof_stdin_detected) {
    313         c = getchar();
    314         if (c == EOF) {
    315             eof_stdin_detected = 1;
    316             if (s == NULL)
    317                 break;
    318             c = '\0';
    319         }
    320         if (s == NULL)
    321             s = p = buf;
    322         if ((size_t)(p - buf) >= mc)
    323             bb_error_msg_and_die("argument line too long");
    324         *p++ = c;
    325         if (c == '\0') {   /* word's delimiter or EOF detected */
    326             /* word loaded */
    327             size_t length = (p - buf);
    328             /* Dont xzalloc - it can be quite big */
    329             cur = xmalloc(offsetof(xlist_t, xstr) + length);
    330             cur->link = NULL;
    331             cur->length = length;
    332             memcpy(cur->xstr, s, length);
    333             if (prev == NULL) {
    334                 list_arg = cur;
    335             } else {
    336                 prev->link = cur;
    337             }
    338             prev = cur;
    339             line_l += length;
    340             if (line_l > mc) {
    341                 /* stop memory usage :-) */
    342                 break;
    343             }
    344             s = NULL;
    345         }
    346     }
    347     return list_arg;
    348 }
    349 #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
     344#endif
     345
     346//usage:#define xargs_trivial_usage
     347//usage:       "[OPTIONS] [PROG ARGS]"
     348//usage:#define xargs_full_usage "\n\n"
     349//usage:       "Run PROG on every item given by stdin\n"
     350//usage:     "\nOptions:"
     351//usage:    IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(
     352//usage:     "\n    -p  Ask user whether to run each command"
     353//usage:    )
     354//usage:     "\n    -r  Don't run command if input is empty"
     355//usage:    IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(
     356//usage:     "\n    -0  Input is separated by NUL characters"
     357//usage:    )
     358//usage:     "\n    -t  Print the command on stderr before execution"
     359//usage:     "\n    -e[STR] STR stops input processing"
     360//usage:     "\n    -n N    Pass no more than N args to PROG"
     361//usage:     "\n    -s N    Pass command line of no more than N bytes"
     362//usage:    IF_FEATURE_XARGS_SUPPORT_TERMOPT(
     363//usage:     "\n    -x  Exit if size is exceeded"
     364//usage:    )
     365//usage:#define xargs_example_usage
     366//usage:       "$ ls | xargs gzip\n"
     367//usage:       "$ find . -name '*.c' -print | xargs rm\n"
    350368
    351369/* Correct regardless of combination of CONFIG_xxx */
     
    356374    OPTBIT_UPTO_SIZE,
    357375    OPTBIT_EOF_STRING,
    358     USE_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
    359     USE_FEATURE_XARGS_SUPPORT_TERMOPT(     OPTBIT_TERMINATE  ,)
    360     USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(   OPTBIT_ZEROTERM   ,)
    361 
    362     OPT_VERBOSE     = 1<<OPTBIT_VERBOSE    ,
    363     OPT_NO_EMPTY    = 1<<OPTBIT_NO_EMPTY   ,
    364     OPT_UPTO_NUMBER = 1<<OPTBIT_UPTO_NUMBER,
    365     OPT_UPTO_SIZE   = 1<<OPTBIT_UPTO_SIZE  ,
    366     OPT_EOF_STRING  = 1<<OPTBIT_EOF_STRING ,
    367     OPT_INTERACTIVE = USE_FEATURE_XARGS_SUPPORT_CONFIRMATION((1<<OPTBIT_INTERACTIVE)) + 0,
    368     OPT_TERMINATE   = USE_FEATURE_XARGS_SUPPORT_TERMOPT(     (1<<OPTBIT_TERMINATE  )) + 0,
    369     OPT_ZEROTERM    = USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(   (1<<OPTBIT_ZEROTERM   )) + 0,
     376    OPTBIT_EOF_STRING1,
     377    IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
     378    IF_FEATURE_XARGS_SUPPORT_TERMOPT(     OPTBIT_TERMINATE  ,)
     379    IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   OPTBIT_ZEROTERM   ,)
     380
     381    OPT_VERBOSE     = 1 << OPTBIT_VERBOSE    ,
     382    OPT_NO_EMPTY    = 1 << OPTBIT_NO_EMPTY   ,
     383    OPT_UPTO_NUMBER = 1 << OPTBIT_UPTO_NUMBER,
     384    OPT_UPTO_SIZE   = 1 << OPTBIT_UPTO_SIZE  ,
     385    OPT_EOF_STRING  = 1 << OPTBIT_EOF_STRING , /* GNU: -e[<param>] */
     386    OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E<param> */
     387    OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0,
     388    OPT_TERMINATE   = IF_FEATURE_XARGS_SUPPORT_TERMOPT(     (1 << OPTBIT_TERMINATE  )) + 0,
     389    OPT_ZEROTERM    = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   (1 << OPTBIT_ZEROTERM   )) + 0,
    370390};
    371 #define OPTION_STR "+trn:s:e::" \
    372     USE_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
    373     USE_FEATURE_XARGS_SUPPORT_TERMOPT(     "x") \
    374     USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(   "0")
    375 
    376 int xargs_main(int argc, char **argv);
     391#define OPTION_STR "+trn:s:e::E:" \
     392    IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
     393    IF_FEATURE_XARGS_SUPPORT_TERMOPT(     "x") \
     394    IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   "0")
     395
     396int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    377397int xargs_main(int argc, char **argv)
    378398{
    379     char **args;
    380     int i, n;
    381     xlist_t *list = NULL;
    382     xlist_t *cur;
     399    int i;
    383400    int child_error = 0;
    384     char *max_args, *max_chars;
     401    char *max_args;
     402    char *max_chars;
     403    char *buf;
     404    unsigned opt;
     405    int n_max_chars;
    385406    int n_max_arg;
    386     size_t n_chars = 0;
    387     long orig_arg_max;
    388     const char *eof_str = "_";
    389     unsigned opt;
    390     size_t n_max_chars;
    391407#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
    392     xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin;
     408    char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin;
    393409#else
    394410#define read_args process_stdin
    395411#endif
    396412
    397     opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &eof_str);
     413    INIT_G();
     414
     415    G.eof_str = NULL;
     416    opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str);
     417
     418    /* -E ""? You may wonder why not just omit -E?
     419     * This is used for portability:
     420     * old xargs was using "_" as default for -E / -e */
     421    if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0')
     422        G.eof_str = NULL;
    398423
    399424    if (opt & OPT_ZEROTERM)
    400         USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
     425        IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
    401426
    402427    argv += optind;
    403428    argc -= optind;
    404     if (!argc) {
     429    if (!argv[0]) {
    405430        /* default behavior is to echo all the filenames */
    406         *argv = (char*)"echo";
     431        *--argv = (char*)"echo";
    407432        argc++;
    408433    }
    409434
    410     orig_arg_max = ARG_MAX;
    411     if (orig_arg_max == -1)
    412         orig_arg_max = LONG_MAX;
    413     orig_arg_max -= 2048;   /* POSIX.2 requires subtracting 2048 */
    414 
     435    /* -s NUM default. fileutils-4.4.2 uses 128k, but I heasitate
     436     * to use such a big value - first need to change code to use
     437     * growable buffer instead of fixed one.
     438     */
     439    n_max_chars = 32 * 1024;
     440    /* Make smaller if system does not allow our default value.
     441     * The Open Group Base Specifications Issue 6:
     442     * "The xargs utility shall limit the command line length such that
     443     * when the command line is invoked, the combined argument
     444     * and environment lists (see the exec family of functions
     445     * in the System Interfaces volume of IEEE Std 1003.1-2001)
     446     * shall not exceed {ARG_MAX}-2048 bytes".
     447     */
     448    {
     449        long arg_max = 0;
     450#if defined _SC_ARG_MAX
     451        arg_max = sysconf(_SC_ARG_MAX) - 2048;
     452#elif defined ARG_MAX
     453        arg_max = ARG_MAX - 2048;
     454#endif
     455        if (arg_max > 0 && n_max_chars > arg_max)
     456            n_max_chars = arg_max;
     457    }
    415458    if (opt & OPT_UPTO_SIZE) {
    416         n_max_chars = xatoul_range(max_chars, 1, orig_arg_max);
    417         for (i = 0; i < argc; i++) {
    418             n_chars += strlen(*argv) + 1;
    419         }
    420         if (n_max_chars < n_chars) {
    421             bb_error_msg_and_die("cannot fit single argument within argument list size limit");
     459        n_max_chars = xatou_range(max_chars, 1, INT_MAX);
     460    }
     461    /* Account for prepended fixed arguments */
     462    {
     463        size_t n_chars = 0;
     464        for (i = 0; argv[i]; i++) {
     465            n_chars += strlen(argv[i]) + 1;
    422466        }
    423467        n_max_chars -= n_chars;
    424     } else {
    425         /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
    426            have it at 1 meg).  Things will work fine with a large ARG_MAX but it
    427            will probably hurt the system more than it needs to; an array of this
    428            size is allocated.  */
    429         if (orig_arg_max > 20 * 1024)
    430             orig_arg_max = 20 * 1024;
    431         n_max_chars = orig_arg_max;
    432     }
    433     max_chars = xmalloc(n_max_chars);
    434 
     468    }
     469    /* Sanity check */
     470    if (n_max_chars <= 0) {
     471        bb_error_msg_and_die("can't fit single argument within argument list size limit");
     472    }
     473
     474    buf = xzalloc(n_max_chars + 1);
     475
     476    n_max_arg = n_max_chars;
    435477    if (opt & OPT_UPTO_NUMBER) {
    436         n_max_arg = xatoul_range(max_args, 1, INT_MAX);
    437     } else {
    438         n_max_arg = n_max_chars;
    439     }
    440 
    441     while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL ||
    442         !(opt & OPT_NO_EMPTY))
    443     {
     478        n_max_arg = xatou_range(max_args, 1, INT_MAX);
     479        /* Not necessary, we use growable args[]: */
     480        /* if (n_max_arg > n_max_chars) n_max_arg = n_max_chars */
     481    }
     482
     483    /* Allocate pointers for execvp */
     484    /* We can statically allocate (argc + n_max_arg + 1) elements
     485     * and do not bother with resizing args[], but on 64-bit machines
     486     * this results in args[] vector which is ~8 times bigger
     487     * than n_max_chars! That is, with n_max_chars == 20k,
     488     * args[] will take 160k (!), which will most likely be
     489     * almost entirely unused.
     490     */
     491    /* See store_param() for matching 256-step growth logic */
     492    G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff));
     493
     494    /* Store the command to be executed, part 1 */
     495    for (i = 0; argv[i]; i++)
     496        G.args[i] = argv[i];
     497
     498    while (1) {
     499        char *rem;
     500
     501        G.idx = argc;
     502        rem = read_args(n_max_chars, n_max_arg, buf);
     503        store_param(NULL);
     504
     505        if (!G.args[argc]) {
     506            if (*rem != '\0')
     507                bb_error_msg_and_die("argument line too long");
     508            if (opt & OPT_NO_EMPTY)
     509                break;
     510        }
    444511        opt |= OPT_NO_EMPTY;
    445         n = 0;
    446         n_chars = 0;
    447 #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
    448         for (cur = list; cur;) {
    449             n_chars += cur->length;
    450             n++;
    451             cur = cur->link;
    452             if (n_chars > n_max_chars || (n == n_max_arg && cur)) {
    453                 if (opt & OPT_TERMINATE)
    454                     bb_error_msg_and_die("argument list too long");
    455                 break;
    456             }
    457         }
    458 #else
    459         for (cur = list; cur; cur = cur->link) {
    460             n_chars += cur->length;
    461             n++;
    462             if (n_chars > n_max_chars || n == n_max_arg) {
    463                 break;
    464             }
    465         }
    466 #endif /* FEATURE_XARGS_SUPPORT_TERMOPT */
    467 
    468         /* allocate pointers for execvp:
    469            argc*arg, n*arg from stdin, NULL */
    470         args = xzalloc((n + argc + 1) * sizeof(char *));
    471 
    472         /* store the command to be executed
    473            (taken from the command line) */
    474         for (i = 0; i < argc; i++)
    475             args[i] = argv[i];
    476         /* (taken from stdin) */
    477         for (cur = list; n; cur = cur->link) {
    478             args[i++] = cur->xstr;
    479             n--;
    480         }
    481512
    482513        if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
     514            const char *fmt = " %s" + 1;
     515            char **args = G.args;
    483516            for (i = 0; args[i]; i++) {
    484                 if (i)
    485                     fputc(' ', stderr);
    486                 fputs(args[i], stderr);
     517                fprintf(stderr, fmt, args[i]);
     518                fmt = " %s";
    487519            }
    488520            if (!(opt & OPT_INTERACTIVE))
    489                 fputc('\n', stderr);
    490         }
     521                bb_putchar_stderr('\n');
     522        }
     523
    491524        if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
    492             child_error = xargs_exec(args);
    493         }
    494 
    495         /* clean up */
    496         for (i = argc; args[i]; i++) {
    497             cur = list;
    498             list = list->link;
    499             free(cur);
    500         }
    501         free(args);
     525            child_error = xargs_exec();
     526        }
     527
    502528        if (child_error > 0 && child_error != 123) {
    503529            break;
    504530        }
    505     }
    506     if (ENABLE_FEATURE_CLEAN_UP)
    507         free(max_chars);
     531
     532        overlapping_strcpy(buf, rem);
     533    } /* while */
     534
     535    if (ENABLE_FEATURE_CLEAN_UP) {
     536        free(G.args);
     537        free(buf);
     538    }
     539
    508540    return child_error;
    509541}
     
    518550    fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
    519551        applet_name);
    520     exit(1);
     552    exit(EXIT_FAILURE);
    521553}
    522554
Note: See TracChangeset for help on using the changeset viewer.