aboutsummaryrefslogtreecommitdiff
path: root/findutils/xargs.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-06-14 00:57:05 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-06-14 00:57:05 +0200
commit7a4021debaa1f89c0ee2ad41f446a8234f8261c7 (patch)
tree3075619c214be7cda3130e9df32465845ce93665 /findutils/xargs.c
parentaaa24e09f98f2694f25abb08cee1a74d7f114b7f (diff)
downloadbusybox-w32-7a4021debaa1f89c0ee2ad41f446a8234f8261c7.tar.gz
busybox-w32-7a4021debaa1f89c0ee2ad41f446a8234f8261c7.tar.bz2
busybox-w32-7a4021debaa1f89c0ee2ad41f446a8234f8261c7.zip
xargs: simplify logic
Removed double-buffering in a linked list. function old new delta store_param - 56 +56 xargs_main 871 840 -31 process_stdin 458 396 -62 process0_stdin 267 143 -124 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/3 up/down: 56/-217) Total: -161 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'findutils/xargs.c')
-rw-r--r--findutils/xargs.c383
1 files changed, 184 insertions, 199 deletions
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 9988e3dd5..857773df9 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -59,10 +59,6 @@
59//config: are not special. 59//config: are not special.
60 60
61#include "libbb.h" 61#include "libbb.h"
62
63/* This is a NOEXEC applet. Be very careful! */
64
65
66/* COMPAT: SYSV version defaults size (and has a max value of) to 470. 62/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
67 We try to make it as large as possible. */ 63 We try to make it as large as possible. */
68#if !defined(ARG_MAX) && defined(_SC_ARG_MAX) 64#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
@@ -72,6 +68,12 @@
72# define ARG_MAX 470 68# define ARG_MAX 470
73#endif 69#endif
74 70
71/* This is a NOEXEC applet. Be very careful! */
72
73
74//#define dbg_msg(...) bb_error_msg(__VA_ARGS__)
75#define dbg_msg(...) ((void)0)
76
75 77
76#ifdef TEST 78#ifdef TEST
77# ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 79# ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
@@ -88,26 +90,36 @@
88# endif 90# endif
89#endif 91#endif
90 92
93
94struct globals {
95 char **args;
96 const char *eof_str;
97 int idx;
98} FIX_ALIASING;
99#define G (*(struct globals*)&bb_common_bufsiz1)
100#define INIT_G() do { } while (0)
101
102
91/* 103/*
92 * This function has special algorithm. 104 * This function has special algorithm.
93 * Don't use fork and include to main! 105 * Don't use fork and include to main!
94 */ 106 */
95static int xargs_exec(char **args) 107static int xargs_exec(void)
96{ 108{
97 int status; 109 int status;
98 110
99 status = spawn_and_wait(args); 111 status = spawn_and_wait(G.args);
100 if (status < 0) { 112 if (status < 0) {
101 bb_simple_perror_msg(args[0]); 113 bb_simple_perror_msg(G.args[0]);
102 return errno == ENOENT ? 127 : 126; 114 return errno == ENOENT ? 127 : 126;
103 } 115 }
104 if (status == 255) { 116 if (status == 255) {
105 bb_error_msg("%s: exited with status 255; aborting", args[0]); 117 bb_error_msg("%s: exited with status 255; aborting", G.args[0]);
106 return 124; 118 return 124;
107 } 119 }
108 if (status >= 0x180) { 120 if (status >= 0x180) {
109 bb_error_msg("%s: terminated by signal %d", 121 bb_error_msg("%s: terminated by signal %d",
110 args[0], status - 0x180); 122 G.args[0], status - 0x180);
111 return 125; 123 return 125;
112 } 124 }
113 if (status) 125 if (status)
@@ -115,51 +127,59 @@ static int xargs_exec(char **args)
115 return 0; 127 return 0;
116} 128}
117 129
118
119typedef struct xlist_t {
120 struct xlist_t *link;
121 size_t length; /* length of xstr[] including NUL */
122 char xstr[1];
123} xlist_t;
124
125/* In POSIX/C locale isspace is only these chars: "\t\n\v\f\r" and space. 130/* In POSIX/C locale isspace is only these chars: "\t\n\v\f\r" and space.
126 * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13. 131 * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13.
127 */ 132 */
128#define ISSPACE(a) ({ unsigned char xargs__isspace = (a) - 9; xargs__isspace == (' ' - 9) || xargs__isspace <= (13 - 9); }) 133#define ISSPACE(a) ({ unsigned char xargs__isspace = (a) - 9; xargs__isspace == (' ' - 9) || xargs__isspace <= (13 - 9); })
129 134
135static void store_param(char *s)
136{
137 /* Grow by 256 elements at once */
138 if (!(G.idx & 0xff)) { /* G.idx == N*256 */
139 /* Enlarge, make G.args[(N+1)*256 - 1] last valid idx */
140 G.args = xrealloc(G.args, sizeof(G.args[0]) * (G.idx + 0x100));
141 }
142 G.args[G.idx++] = s;
143}
144
145/* process[0]_stdin:
146 * Read characters into buf[n_max_chars+1], and when parameter delimiter
147 * is seen, store the address of a new parameter to args[].
148 * If reading discovers that last chars do not form the complete
149 * parameter, the pointer to the first such "tail character" is returned.
150 * (buf has extra byte at the end to accomodate terminating NUL
151 * of "tail characters" string).
152 * Otherwise, the returned pointer points to NUL byte.
153 * The args[] vector is NULL-terminated.
154 * On entry, buf[] may contain some "seed chars" which are to become
155 * the beginning of the first parameter.
156 */
157
130#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 158#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
131static xlist_t* process_stdin(xlist_t *list_arg, 159static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
132 const char *eof_str, size_t n_max_chars, char *buf)
133{ 160{
134#define NORM 0 161#define NORM 0
135#define QUOTE 1 162#define QUOTE 1
136#define BACKSLASH 2 163#define BACKSLASH 2
137#define SPACE 4 164#define SPACE 4
138 char *s = NULL; /* start of the word */ 165 char *s; /* start of the word */
139 char *p = NULL; /* pointer to end of the word */ 166 char *p; /* pointer to end of the word */
140 char q = '\0'; /* quote char */ 167 char q = '\0'; /* quote char */
141 char state = NORM; 168 char state = NORM;
142 char eof_str_detected = 0; 169
143 size_t line_l = 0; /* size of loaded args */ 170 s = buf;
144 xlist_t *cur; 171 p = s + strlen(buf);
145 xlist_t *prev; 172
146 173 /* "goto ret" is used instead of "break" to make control flow
147 prev = cur = list_arg; 174 * more obvious: */
148 while (cur) {
149 prev = cur;
150 line_l += cur->length;
151 cur = cur->link;
152 }
153 175
154 while (1) { 176 while (1) {
155 int c = getchar(); 177 int c = getchar();
156 if (c == EOF) { 178 if (c == EOF) {
157 if (s) 179 if (p != s)
158 goto unexpected_eof; 180 goto close_word;
159 break; 181 goto ret;
160 } 182 }
161 if (eof_str_detected) /* skip till EOF */
162 continue;
163 if (state == BACKSLASH) { 183 if (state == BACKSLASH) {
164 state = NORM; 184 state = NORM;
165 goto set; 185 goto set;
@@ -171,15 +191,13 @@ static xlist_t* process_stdin(xlist_t *list_arg,
171 state = NORM; 191 state = NORM;
172 } else { /* if (state == NORM) */ 192 } else { /* if (state == NORM) */
173 if (ISSPACE(c)) { 193 if (ISSPACE(c)) {
174 if (s) { 194 if (p != s) {
175 unexpected_eof: 195 close_word:
176 state = SPACE; 196 state = SPACE;
177 c = '\0'; 197 c = '\0';
178 goto set; 198 goto set;
179 } 199 }
180 } else { 200 } else {
181 if (s == NULL)
182 s = p = buf;
183 if (c == '\\') { 201 if (c == '\\') {
184 state = BACKSLASH; 202 state = BACKSLASH;
185 } else if (c == '\'' || c == '"') { 203 } else if (c == '\'' || c == '"') {
@@ -187,8 +205,6 @@ static xlist_t* process_stdin(xlist_t *list_arg,
187 state = QUOTE; 205 state = QUOTE;
188 } else { 206 } else {
189 set: 207 set:
190 if ((size_t)(p - buf) >= n_max_chars)
191 bb_error_msg_and_die("argument line too long");
192 *p++ = c; 208 *p++ = c;
193 } 209 }
194 } 210 }
@@ -199,149 +215,128 @@ static xlist_t* process_stdin(xlist_t *list_arg,
199 q == '\'' ? "single" : "double"); 215 q == '\'' ? "single" : "double");
200 } 216 }
201 /* A full word is loaded */ 217 /* A full word is loaded */
202 if (eof_str) { 218 if (G.eof_str) {
203 eof_str_detected = (strcmp(s, eof_str) == 0); 219 if (strcmp(s, G.eof_str) == 0) {
204 } 220 while (getchar() != EOF)
205 if (!eof_str_detected) { 221 continue;
206 size_t length = (p - buf); 222 p = s;
207 /* Dont xzalloc - it can be quite big */ 223 goto ret;
208 cur = xmalloc(offsetof(xlist_t, xstr) + length);
209 cur->link = NULL;
210 cur->length = length;
211 memcpy(cur->xstr, s, length);
212 if (prev == NULL) {
213 list_arg = cur;
214 } else {
215 prev->link = cur;
216 } 224 }
217 prev = cur;
218 line_l += length;
219 if (line_l >= n_max_chars) /* limit memory usage */
220 break;
221 } 225 }
222 s = NULL; 226 n_max_chars -= (p - s);
227 /* if (n_max_chars < 0) impossible */
228 store_param(s);
229 dbg_msg("args[]:'%s'", s);
230 s = p;
231 n_max_arg--;
232 if (n_max_arg == 0 || n_max_chars == 0) {
233 goto ret;
234 }
223 state = NORM; 235 state = NORM;
236 } else /* state != SPACE */
237 if (p - s >= n_max_chars) {
238 dbg_msg("s:'%s' p-s:%d n_max_chars:%d", s, (int)(p-s), n_max_chars);
239 goto ret;
224 } 240 }
225 } 241 }
226 return list_arg; 242 ret:
243 *p = '\0';
244 store_param(NULL);
245 dbg_msg("return:'%s'", s);
246 return s;
227} 247}
228#else 248#else
229/* The variant does not support single quotes, double quotes or backslash */ 249/* The variant does not support single quotes, double quotes or backslash */
230static xlist_t* process_stdin(xlist_t *list_arg, 250static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
231 const char *eof_str, size_t n_max_chars, char *buf)
232{ 251{
233 char eof_str_detected = 0; 252 char *s; /* start of the word */
234 char *s = NULL; /* start of the word */ 253 char *p; /* pointer to end of the word */
235 char *p = NULL; /* pointer to end of the word */ 254
236 size_t line_l = 0; /* size of loaded args */ 255 s = buf;
237 xlist_t *cur; 256 p = s + strlen(buf);
238 xlist_t *prev;
239
240 prev = cur = list_arg;
241 while (cur) {
242 prev = cur;
243 line_l += cur->length;
244 cur = cur->link;
245 }
246 257
247 while (1) { 258 while (1) {
248 int c = getchar(); 259 int c = getchar();
249 if (c == EOF) { 260 if (c == EOF) {
250 if (s == NULL) 261 if (p == s)
251 break; 262 goto ret;
252 }
253 if (eof_str_detected) { /* skip till EOF */
254 continue;
255 } 263 }
256 if (c == EOF || ISSPACE(c)) { 264 if (c == EOF || ISSPACE(c)) {
257 if (s == NULL) 265 if (p == s)
258 continue; 266 continue;
259 c = EOF; 267 c = EOF;
260 } 268 }
261 if (s == NULL)
262 s = p = buf;
263 if ((size_t)(p - buf) >= n_max_chars)
264 bb_error_msg_and_die("argument line too long");
265 *p++ = (c == EOF ? '\0' : c); 269 *p++ = (c == EOF ? '\0' : c);
266 if (c == EOF) { /* word's delimiter or EOF detected */ 270 if (c == EOF) { /* word's delimiter or EOF detected */
267 /* A full word is loaded */ 271 /* A full word is loaded */
268 if (eof_str) { 272 if (G.eof_str) {
269 eof_str_detected = (strcmp(s, eof_str) == 0); 273 if (strcmp(s, G.eof_str) == 0) {
270 } 274 while (getchar() != EOF)
271 if (!eof_str_detected) { 275 continue;
272 size_t length = (p - buf); 276 p = s;
273 /* Dont xzalloc - it can be quite big */ 277 goto ret;
274 cur = xmalloc(offsetof(xlist_t, xstr) + length);
275 cur->link = NULL;
276 cur->length = length;
277 memcpy(cur->xstr, s, length);
278 if (prev == NULL) {
279 list_arg = cur;
280 } else {
281 prev->link = cur;
282 } 278 }
283 prev = cur;
284 line_l += length;
285 if (line_l >= n_max_chars) /* limit memory usage */
286 break;
287 } 279 }
288 s = NULL; 280 n_max_chars -= (p - s);
281 /* if (n_max_chars < 0) impossible */
282 store_param(s);
283 dbg_msg("args[]:'%s'", s);
284 s = p;
285 n_max_arg--;
286 if (n_max_arg == 0 || n_max_chars == 0) {
287 goto ret;
288 }
289 } else /* c != EOF */
290 if (p - s >= n_max_chars) {
291 goto ret;
289 } 292 }
290 } 293 }
291 return list_arg; 294 ret:
295 *p = '\0';
296 store_param(NULL);
297 dbg_msg("return:'%s'", s);
298 return s;
292} 299}
293#endif /* FEATURE_XARGS_SUPPORT_QUOTES */ 300#endif /* FEATURE_XARGS_SUPPORT_QUOTES */
294 301
295#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 302#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
296static xlist_t* process0_stdin(xlist_t *list_arg, 303static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf)
297 const char *eof_str UNUSED_PARAM, size_t n_max_chars, char *buf)
298{ 304{
299 char *s = NULL; /* start of the word */ 305 char *s; /* start of the word */
300 char *p = NULL; /* pointer to end of the word */ 306 char *p; /* pointer to end of the word */
301 size_t line_l = 0; /* size of loaded args */ 307
302 xlist_t *cur; 308 s = buf;
303 xlist_t *prev; 309 p = s + strlen(buf);
304
305 prev = cur = list_arg;
306 while (cur) {
307 prev = cur;
308 line_l += cur->length;
309 cur = cur->link;
310 }
311 310
312 while (1) { 311 while (1) {
313 int c = getchar(); 312 int c = getchar();
314 if (c == EOF) { 313 if (c == EOF) {
315 if (s == NULL) 314 if (p == s)
316 break; 315 goto ret;
317 c = '\0'; 316 c = '\0';
318 } 317 }
319 if (s == NULL)
320 s = p = buf;
321 if ((size_t)(p - buf) >= n_max_chars)
322 bb_error_msg_and_die("argument line too long");
323 *p++ = c; 318 *p++ = c;
324 if (c == '\0') { /* word's delimiter or EOF detected */ 319 if (c == '\0') { /* word's delimiter or EOF detected */
325 /* A full word is loaded */ 320 /* A full word is loaded */
326 size_t length = (p - buf); 321 n_max_chars -= (p - s);
327 /* Dont xzalloc - it can be quite big */ 322 /* if (n_max_chars < 0) impossible */
328 cur = xmalloc(offsetof(xlist_t, xstr) + length); 323 store_param(s);
329 cur->link = NULL; 324 dbg_msg("args[]:'%s'", s);
330 cur->length = length; 325 n_max_arg--;
331 memcpy(cur->xstr, s, length); 326 s = p;
332 if (prev == NULL) { 327 if (n_max_arg == 0 || n_max_chars == 0) {
333 list_arg = cur; 328 goto ret;
334 } else {
335 prev->link = cur;
336 } 329 }
337 prev = cur; 330 } else /* c != '\0' */
338 line_l += length; 331 if (p - s >= n_max_chars) {
339 if (line_l >= n_max_chars) /* limit memory usage */ 332 goto ret;
340 break;
341 s = NULL;
342 } 333 }
343 } 334 }
344 return list_arg; 335 ret:
336 *p = '\0';
337 store_param(NULL);
338 dbg_msg("return:'%s'", s);
339 return s;
345} 340}
346#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ 341#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
347 342
@@ -397,28 +392,30 @@ enum {
397int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 392int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
398int xargs_main(int argc, char **argv) 393int xargs_main(int argc, char **argv)
399{ 394{
400 xlist_t *list = NULL; 395 int i;
401 int child_error = 0; 396 int child_error = 0;
402 char *max_args; 397 char *max_args;
403 char *max_chars; 398 char *max_chars;
404 char *buf; 399 char *buf;
405 int n_max_arg;
406 const char *eof_str = NULL;
407 unsigned opt; 400 unsigned opt;
408 size_t n_max_chars; 401 int n_max_chars;
402 int n_max_arg;
409#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 403#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
410 xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin; 404 char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin;
411#else 405#else
412#define read_args process_stdin 406#define read_args process_stdin
413#endif 407#endif
414 408
415 opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &eof_str, &eof_str); 409 INIT_G();
410
411 G.eof_str = NULL;
412 opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str);
416 413
417 /* -E ""? You may wonder why not just omit -E? 414 /* -E ""? You may wonder why not just omit -E?
418 * This is used for portability: 415 * This is used for portability:
419 * old xargs was using "_" as default for -E / -e */ 416 * old xargs was using "_" as default for -E / -e */
420 if ((opt & OPT_EOF_STRING1) && eof_str[0] == '\0') 417 if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0')
421 eof_str = NULL; 418 G.eof_str = NULL;
422 419
423 if (opt & OPT_ZEROTERM) 420 if (opt & OPT_ZEROTERM)
424 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin); 421 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
@@ -451,93 +448,81 @@ int xargs_main(int argc, char **argv)
451 n_max_chars = 20 * 1024; 448 n_max_chars = 20 * 1024;
452 449
453 if (opt & OPT_UPTO_SIZE) { 450 if (opt & OPT_UPTO_SIZE) {
454 int i;
455 size_t n_chars = 0; 451 size_t n_chars = 0;
456 n_max_chars = xatoul_range(max_chars, 1, INT_MAX); 452 n_max_chars = xatou_range(max_chars, 1, INT_MAX);
457 for (i = 0; argv[i]; i++) { 453 for (i = 0; argv[i]; i++) {
458 n_chars += strlen(argv[i]) + 1; 454 n_chars += strlen(argv[i]) + 1;
459 } 455 }
460 n_max_chars -= n_chars; 456 n_max_chars -= n_chars;
461 if ((ssize_t)n_max_chars <= 0) { 457 if (n_max_chars <= 0) {
462 bb_error_msg_and_die("can't fit single argument within argument list size limit"); 458 bb_error_msg_and_die("can't fit single argument within argument list size limit");
463 } 459 }
464 } 460 }
465 461
466 buf = xmalloc(n_max_chars); 462 buf = xzalloc(n_max_chars + 1);
467 463
468 if (opt & OPT_UPTO_NUMBER) { 464 if (opt & OPT_UPTO_NUMBER) {
469 n_max_arg = xatoul_range(max_args, 1, INT_MAX); 465 n_max_arg = xatou_range(max_args, 1, INT_MAX);
470 if (n_max_arg < n_max_chars) 466 if (n_max_arg < n_max_chars)
471 goto skip; 467 goto skip;
472 } 468 }
473 n_max_arg = n_max_chars; 469 n_max_arg = n_max_chars;
474 skip: 470 skip:
475 471
476 while ((list = read_args(list, eof_str, n_max_chars, buf)) != NULL 472 /* Allocate pointers for execvp */
477 || !(opt & OPT_NO_EMPTY) 473 /* We can statically allocate (argc + n_max_arg + 1) elements
478 ) { 474 * and do not bother with resizing args[], but on 64-bit machines
479 char **args; 475 * this results in args[] vector which is ~8 times bigger
480 xlist_t *cur; 476 * than n_max_chars! That is, with n_max_chars == 20k,
481 int i, n; 477 * args[] will take 160k (!), which will most likely be
482 size_t n_chars; 478 * almost entirely unused.
479 */
480 /* See store_param() for matching 256-step growth logic */
481 G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff));
483 482
484 opt |= OPT_NO_EMPTY; 483 /* Store the command to be executed, part 1 */
484 for (i = 0; argv[i]; i++)
485 G.args[i] = argv[i];
485 486
486 /* take args from list, not exceeding arg and char limits */ 487 while (1) {
487 n_chars = 0; 488 char *rem;
488 n = 0; 489
489 for (cur = list; cur; cur = cur->link) { 490 G.idx = argc;
490 n_chars += cur->length; 491 rem = read_args(n_max_chars, n_max_arg, buf);
491 if (n_chars > n_max_chars || n >= n_max_arg) {
492 if (opt & OPT_TERMINATE)
493 bb_error_msg_and_die("argument list too long");
494 break;
495 }
496 n++;
497 }
498 492
499 /* allocate pointers for execvp */ 493 if (!G.args[argc]) {
500 args = xzalloc(sizeof(args[0]) * (argc + n + 1)); 494 if (*rem != '\0')
501 495 bb_error_msg_and_die("argument line too long");
502 /* store the command to be executed 496 if (opt & OPT_NO_EMPTY)
503 * (taken from the command line) */ 497 break;
504 for (i = 0; argv[i]; i++)
505 args[i] = argv[i];
506 /* (taken from stdin) */
507 for (cur = list; n; cur = cur->link) {
508 args[i++] = cur->xstr;
509 n--;
510 } 498 }
499 opt |= OPT_NO_EMPTY;
511 500
512 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) { 501 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
513 for (i = 0; args[i]; i++) { 502 for (i = 0; G.args[i]; i++) {
514 if (i) 503 if (i)
515 bb_putchar_stderr(' '); 504 bb_putchar_stderr(' ');
516 fputs(args[i], stderr); 505 fputs(G.args[i], stderr);
517 } 506 }
518 if (!(opt & OPT_INTERACTIVE)) 507 if (!(opt & OPT_INTERACTIVE))
519 bb_putchar_stderr('\n'); 508 bb_putchar_stderr('\n');
520 } 509 }
521 510
522 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { 511 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
523 child_error = xargs_exec(args); 512 child_error = xargs_exec();
524 }
525
526 /* remove list elements which we consumed */
527 for (i = argc; args[i]; i++) {
528 cur = list;
529 list = list->link;
530 free(cur);
531 } 513 }
532 free(args);
533 514
534 if (child_error > 0 && child_error != 123) { 515 if (child_error > 0 && child_error != 123) {
535 break; 516 break;
536 } 517 }
518
519 overlapping_strcpy(buf, rem);
537 } /* while */ 520 } /* while */
538 521
539 if (ENABLE_FEATURE_CLEAN_UP) 522 if (ENABLE_FEATURE_CLEAN_UP) {
523 free(G.args);
540 free(buf); 524 free(buf);
525 }
541 526
542 return child_error; 527 return child_error;
543} 528}