Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/findutils/xargs.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/findutils/xargs.c
r1765 r2725 2 2 /* 3 3 * Mini xargs implementation for busybox 4 * Options are supported: "-prtx -n max_arg -s max_chars -e[ouf_str]"5 4 * 6 5 * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru> … … 11 10 * and David MacKenzie <djm@gnu.ai.mit.edu>. 12 11 * 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. 14 13 * 15 14 * xargs is described in the Single Unix Specification v3 at 16 15 * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html 17 *18 16 */ 19 17 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 20 61 #include "libbb.h" 21 62 … … 23 64 24 65 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) 33 68 34 69 … … 48 83 #endif 49 84 85 86 struct 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 50 95 /* 51 52 53 */54 static int xargs_exec( char **args)96 * This function has special algorithm. 97 * Don't use fork and include to main! 98 */ 99 static int xargs_exec(void) 55 100 { 56 101 int status; 57 102 58 status = spawn_and_wait( args);103 status = spawn_and_wait(G.args); 59 104 if (status < 0) { 60 bb_ perror_msg("%s",args[0]);105 bb_simple_perror_msg(G.args[0]); 61 106 return errno == ENOENT ? 127 : 126; 62 107 } 63 108 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]); 65 110 return 124; 66 111 } 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) { 75 113 bb_error_msg("%s: terminated by signal %d", 76 args[0], status - 1000);114 G.args[0], status - 0x180); 77 115 return 125; 78 116 } … … 82 120 } 83 121 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 127 static 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 */ 96 148 97 149 #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) 150 static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf) 100 151 { 101 152 #define NORM 0 … … 103 154 #define BACKSLASH 2 104 155 #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 */ 109 157 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 117 166 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(); 126 168 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 } 134 173 if (state == BACKSLASH) { 135 174 state = NORM; 136 175 goto set; 137 } else if (state == QUOTE) { 176 } 177 if (state == QUOTE) { 138 178 if (c != q) 139 179 goto set; … … 142 182 } else { /* if (state == NORM) */ 143 183 if (ISSPACE(c)) { 144 if ( s) {145 unexpected_eof:184 if (p != s) { 185 close_word: 146 186 state = SPACE; 147 187 c = '\0'; … … 149 189 } 150 190 } else { 151 if (s == NULL)152 s = p = buf;153 191 if (c == '\\') { 154 192 state = BACKSLASH; … … 158 196 } else { 159 197 set: 160 if ((size_t)(p - buf) >= mc)161 bb_error_msg_and_die("argument line too long");162 198 *p++ = c; 163 199 } … … 169 205 q == '\'' ? "single" : "double"); 170 206 } 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; 186 214 } 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 } 195 223 state = NORM; 196 224 } 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; 199 234 } 200 235 #else 201 236 /* 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; 237 static 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 215 244 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(); 224 246 if (c == EOF) { 225 eof_stdin_detected = 1; 226 } 227 if (eof_str_detected) 228 continue; 247 if (p == s) 248 goto ret; 249 } 229 250 if (c == EOF || ISSPACE(c)) { 230 if ( s == NULL)251 if (p == s) 231 252 continue; 232 253 c = EOF; 233 254 } 234 if (s == NULL)235 s = p = buf;236 if ((p - buf) >= mc)237 bb_error_msg_and_die("argument line too long");238 255 *p++ = (c == EOF ? '\0' : c); 239 256 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; 255 264 } 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; 267 283 } 268 284 #endif /* FEATURE_XARGS_SUPPORT_QUOTES */ 269 285 286 #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 287 static 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 */ 270 323 271 324 #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION … … 278 331 int c, savec; 279 332 280 tty_stream = xfopen (CURRENT_TTY, "r");333 tty_stream = xfopen_for_read(CURRENT_TTY); 281 334 fputs(" ?...", stderr); 282 fflush (stderr);335 fflush_all(); 283 336 c = savec = getc(tty_stream); 284 337 while (c != EOF && c != '\n') … … 289 342 #else 290 343 # 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" 350 368 351 369 /* Correct regardless of combination of CONFIG_xxx */ … … 356 374 OPTBIT_UPTO_SIZE, 357 375 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, 370 390 }; 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 396 int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 377 397 int xargs_main(int argc, char **argv) 378 398 { 379 char **args; 380 int i, n; 381 xlist_t *list = NULL; 382 xlist_t *cur; 399 int i; 383 400 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; 385 406 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;391 407 #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; 393 409 #else 394 410 #define read_args process_stdin 395 411 #endif 396 412 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; 398 423 399 424 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); 401 426 402 427 argv += optind; 403 428 argc -= optind; 404 if (!arg c) {429 if (!argv[0]) { 405 430 /* default behavior is to echo all the filenames */ 406 * argv = (char*)"echo";431 *--argv = (char*)"echo"; 407 432 argc++; 408 433 } 409 434 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 } 415 458 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; 422 466 } 423 467 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; 435 477 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 } 444 511 opt |= OPT_NO_EMPTY; 445 n = 0;446 n_chars = 0;447 #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT448 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 #else459 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 executed473 (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 }481 512 482 513 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { 514 const char *fmt = " %s" + 1; 515 char **args = G.args; 483 516 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"; 487 519 } 488 520 if (!(opt & OPT_INTERACTIVE)) 489 fputc('\n', stderr); 490 } 521 bb_putchar_stderr('\n'); 522 } 523 491 524 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 502 528 if (child_error > 0 && child_error != 123) { 503 529 break; 504 530 } 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 508 540 return child_error; 509 541 } … … 518 550 fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n", 519 551 applet_name); 520 exit( 1);552 exit(EXIT_FAILURE); 521 553 } 522 554
Note:
See TracChangeset
for help on using the changeset viewer.