aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-06-13 12:43:54 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-06-13 12:43:54 +0200
commitaaa24e09f98f2694f25abb08cee1a74d7f114b7f (patch)
tree8aef060e50ebf3d2852a881962f392589933c230
parent1613de85d9203fa8628569e8e722899b184b24d8 (diff)
downloadbusybox-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.c99
-rwxr-xr-xtestsuite/xargs.tests12
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 */
95static int xargs_exec(char **args) 95static 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
119typedef struct xlist_t { 119typedef 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
131static xlist_t* process_stdin(xlist_t *list_arg, 131static 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 */
230static xlist_t* process_stdin(xlist_t *list_arg, 230static 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. */
300static 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
319static xlist_t* process0_stdin(xlist_t *list_arg, 296static 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. */
352static 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 */
372enum { 371enum {
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
29testing "xargs -s7 can take one-char input" \ 29testing "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
34testing "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
39testing "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
34exit $FAILCOUNT 44exit $FAILCOUNT