diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-13 12:43:54 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-13 12:43:54 +0200 |
commit | aaa24e09f98f2694f25abb08cee1a74d7f114b7f (patch) | |
tree | 8aef060e50ebf3d2852a881962f392589933c230 | |
parent | 1613de85d9203fa8628569e8e722899b184b24d8 (diff) | |
download | busybox-w32-aaa24e09f98f2694f25abb08cee1a74d7f114b7f.tar.gz busybox-w32-aaa24e09f98f2694f25abb08cee1a74d7f114b7f.tar.bz2 busybox-w32-aaa24e09f98f2694f25abb08cee1a74d7f114b7f.zip |
xargs: fix accounting of -sNUM
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | findutils/xargs.c | 99 | ||||
-rwxr-xr-x | testsuite/xargs.tests | 12 |
2 files changed, 57 insertions, 54 deletions
diff --git a/findutils/xargs.c b/findutils/xargs.c index 9ee5833e5..9988e3dd5 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c | |||
@@ -89,9 +89,9 @@ | |||
89 | #endif | 89 | #endif |
90 | 90 | ||
91 | /* | 91 | /* |
92 | This function has special algorithm. | 92 | * This function has special algorithm. |
93 | Don't use fork and include to main! | 93 | * Don't use fork and include to main! |
94 | */ | 94 | */ |
95 | static int xargs_exec(char **args) | 95 | static int xargs_exec(char **args) |
96 | { | 96 | { |
97 | int status; | 97 | int status; |
@@ -118,7 +118,7 @@ static int xargs_exec(char **args) | |||
118 | 118 | ||
119 | typedef struct xlist_t { | 119 | typedef struct xlist_t { |
120 | struct xlist_t *link; | 120 | struct xlist_t *link; |
121 | size_t length; | 121 | size_t length; /* length of xstr[] including NUL */ |
122 | char xstr[1]; | 122 | char xstr[1]; |
123 | } xlist_t; | 123 | } xlist_t; |
124 | 124 | ||
@@ -129,7 +129,7 @@ typedef struct xlist_t { | |||
129 | 129 | ||
130 | #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES | 130 | #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES |
131 | static xlist_t* process_stdin(xlist_t *list_arg, | 131 | static xlist_t* process_stdin(xlist_t *list_arg, |
132 | const char *eof_str, size_t mc, char *buf) | 132 | const char *eof_str, size_t n_max_chars, char *buf) |
133 | { | 133 | { |
134 | #define NORM 0 | 134 | #define NORM 0 |
135 | #define QUOTE 1 | 135 | #define QUOTE 1 |
@@ -187,7 +187,7 @@ static xlist_t* process_stdin(xlist_t *list_arg, | |||
187 | state = QUOTE; | 187 | state = QUOTE; |
188 | } else { | 188 | } else { |
189 | set: | 189 | set: |
190 | if ((size_t)(p - buf) >= mc) | 190 | if ((size_t)(p - buf) >= n_max_chars) |
191 | bb_error_msg_and_die("argument line too long"); | 191 | bb_error_msg_and_die("argument line too long"); |
192 | *p++ = c; | 192 | *p++ = c; |
193 | } | 193 | } |
@@ -216,7 +216,7 @@ static xlist_t* process_stdin(xlist_t *list_arg, | |||
216 | } | 216 | } |
217 | prev = cur; | 217 | prev = cur; |
218 | line_l += length; | 218 | line_l += length; |
219 | if (line_l > mc) /* limit stop memory usage */ | 219 | if (line_l >= n_max_chars) /* limit memory usage */ |
220 | break; | 220 | break; |
221 | } | 221 | } |
222 | s = NULL; | 222 | s = NULL; |
@@ -228,7 +228,7 @@ static xlist_t* process_stdin(xlist_t *list_arg, | |||
228 | #else | 228 | #else |
229 | /* The variant does not support single quotes, double quotes or backslash */ | 229 | /* The variant does not support single quotes, double quotes or backslash */ |
230 | static xlist_t* process_stdin(xlist_t *list_arg, | 230 | static xlist_t* process_stdin(xlist_t *list_arg, |
231 | const char *eof_str, size_t mc, char *buf) | 231 | const char *eof_str, size_t n_max_chars, char *buf) |
232 | { | 232 | { |
233 | char eof_str_detected = 0; | 233 | char eof_str_detected = 0; |
234 | char *s = NULL; /* start of the word */ | 234 | char *s = NULL; /* start of the word */ |
@@ -260,7 +260,7 @@ static xlist_t* process_stdin(xlist_t *list_arg, | |||
260 | } | 260 | } |
261 | if (s == NULL) | 261 | if (s == NULL) |
262 | s = p = buf; | 262 | s = p = buf; |
263 | if ((size_t)(p - buf) >= mc) | 263 | if ((size_t)(p - buf) >= n_max_chars) |
264 | bb_error_msg_and_die("argument line too long"); | 264 | bb_error_msg_and_die("argument line too long"); |
265 | *p++ = (c == EOF ? '\0' : c); | 265 | *p++ = (c == EOF ? '\0' : c); |
266 | if (c == EOF) { /* word's delimiter or EOF detected */ | 266 | if (c == EOF) { /* word's delimiter or EOF detected */ |
@@ -282,7 +282,7 @@ static xlist_t* process_stdin(xlist_t *list_arg, | |||
282 | } | 282 | } |
283 | prev = cur; | 283 | prev = cur; |
284 | line_l += length; | 284 | line_l += length; |
285 | if (line_l > mc) /* limit stop memory usage */ | 285 | if (line_l >= n_max_chars) /* limit memory usage */ |
286 | break; | 286 | break; |
287 | } | 287 | } |
288 | s = NULL; | 288 | s = NULL; |
@@ -292,32 +292,9 @@ static xlist_t* process_stdin(xlist_t *list_arg, | |||
292 | } | 292 | } |
293 | #endif /* FEATURE_XARGS_SUPPORT_QUOTES */ | 293 | #endif /* FEATURE_XARGS_SUPPORT_QUOTES */ |
294 | 294 | ||
295 | |||
296 | #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION | ||
297 | /* Prompt the user for a response, and | ||
298 | if the user responds affirmatively, return true; | ||
299 | otherwise, return false. Uses "/dev/tty", not stdin. */ | ||
300 | static int xargs_ask_confirmation(void) | ||
301 | { | ||
302 | FILE *tty_stream; | ||
303 | int c, savec; | ||
304 | |||
305 | tty_stream = xfopen_for_read(CURRENT_TTY); | ||
306 | fputs(" ?...", stderr); | ||
307 | fflush_all(); | ||
308 | c = savec = getc(tty_stream); | ||
309 | while (c != EOF && c != '\n') | ||
310 | c = getc(tty_stream); | ||
311 | fclose(tty_stream); | ||
312 | return (savec == 'y' || savec == 'Y'); | ||
313 | } | ||
314 | #else | ||
315 | # define xargs_ask_confirmation() 1 | ||
316 | #endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */ | ||
317 | |||
318 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM | 295 | #if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM |
319 | static xlist_t* process0_stdin(xlist_t *list_arg, | 296 | static xlist_t* process0_stdin(xlist_t *list_arg, |
320 | const char *eof_str UNUSED_PARAM, size_t mc, char *buf) | 297 | const char *eof_str UNUSED_PARAM, size_t n_max_chars, char *buf) |
321 | { | 298 | { |
322 | char *s = NULL; /* start of the word */ | 299 | char *s = NULL; /* start of the word */ |
323 | char *p = NULL; /* pointer to end of the word */ | 300 | char *p = NULL; /* pointer to end of the word */ |
@@ -341,7 +318,7 @@ static xlist_t* process0_stdin(xlist_t *list_arg, | |||
341 | } | 318 | } |
342 | if (s == NULL) | 319 | if (s == NULL) |
343 | s = p = buf; | 320 | s = p = buf; |
344 | if ((size_t)(p - buf) >= mc) | 321 | if ((size_t)(p - buf) >= n_max_chars) |
345 | bb_error_msg_and_die("argument line too long"); | 322 | bb_error_msg_and_die("argument line too long"); |
346 | *p++ = c; | 323 | *p++ = c; |
347 | if (c == '\0') { /* word's delimiter or EOF detected */ | 324 | if (c == '\0') { /* word's delimiter or EOF detected */ |
@@ -359,7 +336,7 @@ static xlist_t* process0_stdin(xlist_t *list_arg, | |||
359 | } | 336 | } |
360 | prev = cur; | 337 | prev = cur; |
361 | line_l += length; | 338 | line_l += length; |
362 | if (line_l > mc) /* limit stop memory usage */ | 339 | if (line_l >= n_max_chars) /* limit memory usage */ |
363 | break; | 340 | break; |
364 | s = NULL; | 341 | s = NULL; |
365 | } | 342 | } |
@@ -368,6 +345,28 @@ static xlist_t* process0_stdin(xlist_t *list_arg, | |||
368 | } | 345 | } |
369 | #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ | 346 | #endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ |
370 | 347 | ||
348 | #if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION | ||
349 | /* Prompt the user for a response, and | ||
350 | if the user responds affirmatively, return true; | ||
351 | otherwise, return false. Uses "/dev/tty", not stdin. */ | ||
352 | static int xargs_ask_confirmation(void) | ||
353 | { | ||
354 | FILE *tty_stream; | ||
355 | int c, savec; | ||
356 | |||
357 | tty_stream = xfopen_for_read(CURRENT_TTY); | ||
358 | fputs(" ?...", stderr); | ||
359 | fflush_all(); | ||
360 | c = savec = getc(tty_stream); | ||
361 | while (c != EOF && c != '\n') | ||
362 | c = getc(tty_stream); | ||
363 | fclose(tty_stream); | ||
364 | return (savec == 'y' || savec == 'Y'); | ||
365 | } | ||
366 | #else | ||
367 | # define xargs_ask_confirmation() 1 | ||
368 | #endif | ||
369 | |||
371 | /* Correct regardless of combination of CONFIG_xxx */ | 370 | /* Correct regardless of combination of CONFIG_xxx */ |
372 | enum { | 371 | enum { |
373 | OPTBIT_VERBOSE = 0, | 372 | OPTBIT_VERBOSE = 0, |
@@ -468,9 +467,11 @@ int xargs_main(int argc, char **argv) | |||
468 | 467 | ||
469 | if (opt & OPT_UPTO_NUMBER) { | 468 | if (opt & OPT_UPTO_NUMBER) { |
470 | n_max_arg = xatoul_range(max_args, 1, INT_MAX); | 469 | n_max_arg = xatoul_range(max_args, 1, INT_MAX); |
471 | } else { | 470 | if (n_max_arg < n_max_chars) |
472 | n_max_arg = n_max_chars; | 471 | goto skip; |
473 | } | 472 | } |
473 | n_max_arg = n_max_chars; | ||
474 | skip: | ||
474 | 475 | ||
475 | while ((list = read_args(list, eof_str, n_max_chars, buf)) != NULL | 476 | while ((list = read_args(list, eof_str, n_max_chars, buf)) != NULL |
476 | || !(opt & OPT_NO_EMPTY) | 477 | || !(opt & OPT_NO_EMPTY) |
@@ -478,30 +479,22 @@ int xargs_main(int argc, char **argv) | |||
478 | char **args; | 479 | char **args; |
479 | xlist_t *cur; | 480 | xlist_t *cur; |
480 | int i, n; | 481 | int i, n; |
481 | size_t n_chars = 0; | 482 | size_t n_chars; |
482 | 483 | ||
483 | opt |= OPT_NO_EMPTY; | 484 | opt |= OPT_NO_EMPTY; |
485 | |||
486 | /* take args from list, not exceeding arg and char limits */ | ||
487 | n_chars = 0; | ||
484 | n = 0; | 488 | n = 0; |
485 | #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT | 489 | for (cur = list; cur; cur = cur->link) { |
486 | for (cur = list; cur;) { | ||
487 | n_chars += cur->length; | 490 | n_chars += cur->length; |
488 | n++; | 491 | if (n_chars > n_max_chars || n >= n_max_arg) { |
489 | cur = cur->link; | ||
490 | if (n_chars > n_max_chars || (n == n_max_arg && cur)) { | ||
491 | if (opt & OPT_TERMINATE) | 492 | if (opt & OPT_TERMINATE) |
492 | bb_error_msg_and_die("argument list too long"); | 493 | bb_error_msg_and_die("argument list too long"); |
493 | break; | 494 | break; |
494 | } | 495 | } |
495 | } | ||
496 | #else | ||
497 | for (cur = list; cur; cur = cur->link) { | ||
498 | n_chars += cur->length; | ||
499 | n++; | 496 | n++; |
500 | if (n_chars > n_max_chars || n == n_max_arg) { | ||
501 | break; | ||
502 | } | ||
503 | } | 497 | } |
504 | #endif | ||
505 | 498 | ||
506 | /* allocate pointers for execvp */ | 499 | /* allocate pointers for execvp */ |
507 | args = xzalloc(sizeof(args[0]) * (argc + n + 1)); | 500 | args = xzalloc(sizeof(args[0]) * (argc + n + 1)); |
@@ -530,7 +523,7 @@ int xargs_main(int argc, char **argv) | |||
530 | child_error = xargs_exec(args); | 523 | child_error = xargs_exec(args); |
531 | } | 524 | } |
532 | 525 | ||
533 | /* clean up */ | 526 | /* remove list elements which we consumed */ |
534 | for (i = argc; args[i]; i++) { | 527 | for (i = argc; args[i]; i++) { |
535 | cur = list; | 528 | cur = list; |
536 | list = list->link; | 529 | list = list->link; |
diff --git a/testsuite/xargs.tests b/testsuite/xargs.tests index c73363038..6463252bf 100755 --- a/testsuite/xargs.tests +++ b/testsuite/xargs.tests | |||
@@ -27,8 +27,18 @@ testing "xargs does not stop on underscore ('new' GNU behavior)" \ | |||
27 | "" "a\n_\nb\n" | 27 | "" "a\n_\nb\n" |
28 | 28 | ||
29 | testing "xargs -s7 can take one-char input" \ | 29 | testing "xargs -s7 can take one-char input" \ |
30 | "xargs -s7" \ | 30 | "xargs -s7 echo" \ |
31 | "a\n" \ | 31 | "a\n" \ |
32 | "" "a\n" | 32 | "" "a\n" |
33 | 33 | ||
34 | testing "xargs -sNUM test 1" \ | ||
35 | "xargs -ts25 echo 2>&1 >/dev/null" \ | ||
36 | "echo 1 2 3 4 5 6 7 8 9 0\n""echo 1 2 3 4 5 6 7 8 9\n""echo 00\n" \ | ||
37 | "" "1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 00\n" | ||
38 | |||
39 | testing "xargs -sNUM test 2" \ | ||
40 | "xargs -ts25 echo 1 2>&1 >/dev/null" \ | ||
41 | "echo 1 2 3 4 5 6 7 8 9 0\n""echo 1 2 3 4 5 6 7 8 9\n""echo 1 00\n" \ | ||
42 | "" "2 3 4 5 6 7 8 9 0 2 3 4 5 6 7 8 9 00\n" | ||
43 | |||
34 | exit $FAILCOUNT | 44 | exit $FAILCOUNT |