blob: d067a3f480f6ca38739ea1808bf5ce6ba4820222 [file] [log] [blame]
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +00001/* vi: set sw=4 ts=4: */
Eric Andersen5b176932000-09-22 20:22:28 +00002/*
Eric Andersena37d5b72000-09-23 06:10:14 +00003 * Mini xargs implementation for busybox
Glenn L McGrath61796942003-10-10 12:10:18 +00004 * Options are supported: "-prtx -n max_arg -s max_chars -e[ouf_str]"
Eric Andersen5b176932000-09-22 20:22:28 +00005 *
Glenn L McGrath61796942003-10-10 12:10:18 +00006 * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru>
Glenn L McGrathf57674e2002-11-10 21:47:17 +00007 *
Glenn L McGrath61796942003-10-10 12:10:18 +00008 * Special thanks
Eric Andersenaff114c2004-04-14 17:51:38 +00009 * - Mark Whitley and Glenn McGrath for stimulus to rewrite :)
Glenn L McGrath61796942003-10-10 12:10:18 +000010 * - Mike Rendell <michael@cs.mun.ca>
11 * and David MacKenzie <djm@gnu.ai.mit.edu>.
Eric Andersen5b176932000-09-22 20:22:28 +000012 *
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000013 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersena37d5b72000-09-23 06:10:14 +000014 *
Glenn L McGrath40c94892003-10-30 22:51:33 +000015 * xargs is described in the Single Unix Specification v3 at
16 * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html
17 *
Eric Andersen5b176932000-09-22 20:22:28 +000018 */
Eric Andersen92a61c12000-09-22 20:01:23 +000019
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000020#include "busybox.h"
Eric Andersen92a61c12000-09-22 20:01:23 +000021
Glenn L McGrath61796942003-10-10 12:10:18 +000022/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
23 We try to make it as large as possible. */
24#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
25#define ARG_MAX sysconf (_SC_ARG_MAX)
26#endif
27#ifndef ARG_MAX
28#define ARG_MAX 470
29#endif
30
31
32#ifdef TEST
33# ifndef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
34# define CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
35# endif
36# ifndef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
37# define CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
38# endif
39# ifndef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
40# define CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
41# endif
42# ifndef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
43# define CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
44# endif
45#endif
46
Glenn L McGrathf57674e2002-11-10 21:47:17 +000047/*
48 This function have special algorithm.
49 Don`t use fork and include to main!
50*/
Glenn L McGrath09c295a2003-10-30 22:47:16 +000051static int xargs_exec(char *const *args)
Glenn L McGrathf57674e2002-11-10 21:47:17 +000052{
Glenn L McGrath09c295a2003-10-30 22:47:16 +000053 pid_t p;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +000054 volatile int exec_errno = 0; /* shared vfork stack */
Glenn L McGrath61796942003-10-10 12:10:18 +000055
Glenn L McGrath09c295a2003-10-30 22:47:16 +000056 if ((p = vfork()) >= 0) {
57 if (p == 0) {
58 /* vfork -- child */
59 execvp(args[0], args);
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +000060 exec_errno = errno; /* set error to shared stack */
Glenn L McGrath09c295a2003-10-30 22:47:16 +000061 _exit(1);
62 } else {
63 /* vfork -- parent */
64 int status;
65
66 while (wait(&status) == (pid_t) - 1)
67 if (errno != EINTR)
68 break;
69 if (exec_errno) {
70 errno = exec_errno;
71 bb_perror_msg("%s", args[0]);
72 return exec_errno == ENOENT ? 127 : 126;
73 } else {
74 if (WEXITSTATUS(status) == 255) {
Eric Andersen252183e2003-10-31 08:19:44 +000075 bb_error_msg("%s: exited with status 255; aborting", args[0]);
Glenn L McGrath09c295a2003-10-30 22:47:16 +000076 return 124;
77 }
78 if (WIFSTOPPED(status)) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +000079 bb_error_msg("%s: stopped by signal %d",
Eric Andersen252183e2003-10-31 08:19:44 +000080 args[0], WSTOPSIG(status));
Glenn L McGrath09c295a2003-10-30 22:47:16 +000081 return 125;
82 }
83 if (WIFSIGNALED(status)) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +000084 bb_error_msg("%s: terminated by signal %d",
Eric Andersen252183e2003-10-31 08:19:44 +000085 args[0], WTERMSIG(status));
Glenn L McGrath09c295a2003-10-30 22:47:16 +000086 return 125;
87 }
88 if (WEXITSTATUS(status) != 0)
89 return 123;
90 return 0;
91 }
92 }
Glenn L McGrath99825962003-10-09 11:06:45 +000093 } else {
Glenn L McGrath09c295a2003-10-30 22:47:16 +000094 bb_perror_msg_and_die("vfork");
Glenn L McGrath61796942003-10-10 12:10:18 +000095 }
Glenn L McGrath61796942003-10-10 12:10:18 +000096}
Glenn L McGrath99825962003-10-09 11:06:45 +000097
Glenn L McGrath61796942003-10-10 12:10:18 +000098
99typedef struct xlist_s {
100 char *data;
101 size_t lenght;
102 struct xlist_s *link;
103} xlist_t;
104
105static int eof_stdin_detected;
106
107#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
108#define ISSPACE(c) (ISBLANK (c) || (c) == '\n' || (c) == '\r' \
109 || (c) == '\f' || (c) == '\v')
110
111#ifdef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000112static xlist_t *process_stdin(xlist_t * list_arg,
Eric Andersen252183e2003-10-31 08:19:44 +0000113 const char *eof_str, size_t mc, char *buf)
Glenn L McGrath61796942003-10-10 12:10:18 +0000114{
115#define NORM 0
116#define QUOTE 1
117#define BACKSLASH 2
118#define SPACE 4
119
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000120 char *s = NULL; /* start word */
121 char *p = NULL; /* pointer to end word */
122 char q = 0; /* quote char */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000123 char state = NORM;
124 char eof_str_detected = 0;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000125 size_t line_l = 0; /* size loaded args line */
126 int c; /* current char */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000127 xlist_t *cur;
128 xlist_t *prev;
Glenn L McGrath61796942003-10-10 12:10:18 +0000129
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000130 for (prev = cur = list_arg; cur; cur = cur->link) {
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000131 line_l += cur->lenght; /* previous allocated */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000132 if (prev != cur)
133 prev = prev->link;
Glenn L McGrath61796942003-10-10 12:10:18 +0000134 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000135
136 while (!eof_stdin_detected) {
137 c = getchar();
138 if (c == EOF) {
139 eof_stdin_detected++;
140 if (s)
141 goto unexpected_eof;
142 break;
Glenn L McGrath61796942003-10-10 12:10:18 +0000143 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000144 if (eof_str_detected)
145 continue;
146 if (state == BACKSLASH) {
147 state = NORM;
148 goto set;
149 } else if (state == QUOTE) {
150 if (c == q) {
151 q = 0;
152 state = NORM;
153 } else {
154 goto set;
155 }
Eric Andersen252183e2003-10-31 08:19:44 +0000156 } else { /* if(state == NORM) */
Glenn L McGrath61796942003-10-10 12:10:18 +0000157
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000158 if (ISSPACE(c)) {
159 if (s) {
Eric Andersen252183e2003-10-31 08:19:44 +0000160unexpected_eof:
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000161 state = SPACE;
162 c = 0;
163 goto set;
164 }
165 } else {
166 if (s == NULL)
167 s = p = buf;
168 if (c == '\\') {
169 state = BACKSLASH;
170 } else if (c == '\'' || c == '"') {
171 q = c;
172 state = QUOTE;
173 } else {
Eric Andersen252183e2003-10-31 08:19:44 +0000174set:
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000175 if ((size_t)(p - buf) >= mc)
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000176 bb_error_msg_and_die("argument line too long");
177 *p++ = c;
178 }
179 }
180 }
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000181 if (state == SPACE) { /* word's delimiter or EOF detected */
Eric Andersen252183e2003-10-31 08:19:44 +0000182 if (q) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000183 bb_error_msg_and_die("unmatched %s quote",
Eric Andersen252183e2003-10-31 08:19:44 +0000184 q == '\'' ? "single" : "double");
185 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000186 /* word loaded */
187 if (eof_str) {
188 eof_str_detected = strcmp(s, eof_str) == 0;
189 }
190 if (!eof_str_detected) {
191 size_t lenght = (p - buf);
192
193 cur = xmalloc(sizeof(xlist_t) + lenght);
194 cur->data = memcpy(cur + 1, s, lenght);
195 cur->lenght = lenght;
196 cur->link = NULL;
197 if (prev == NULL) {
198 list_arg = cur;
199 } else {
200 prev->link = cur;
201 }
202 prev = cur;
203 line_l += lenght;
204 if (line_l > mc) {
205 /* stop memory usage :-) */
206 break;
207 }
208 }
209 s = NULL;
210 state = NORM;
211 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000212 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000213 return list_arg;
Glenn L McGrathf57674e2002-11-10 21:47:17 +0000214}
Glenn L McGrath61796942003-10-10 12:10:18 +0000215#else
Eric Andersen252183e2003-10-31 08:19:44 +0000216/* The variant does not support single quotes, double quotes or backslash */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000217static xlist_t *process_stdin(xlist_t * list_arg,
Eric Andersen252183e2003-10-31 08:19:44 +0000218 const char *eof_str, size_t mc, char *buf)
Eric Andersen92a61c12000-09-22 20:01:23 +0000219{
Eric Andersen92a61c12000-09-22 20:01:23 +0000220
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000221 int c; /* current char */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000222 int eof_str_detected = 0;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000223 char *s = NULL; /* start word */
224 char *p = NULL; /* pointer to end word */
225 size_t line_l = 0; /* size loaded args line */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000226 xlist_t *cur;
227 xlist_t *prev;
Glenn L McGrathadd3ead2003-10-04 14:44:27 +0000228
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000229 for (prev = cur = list_arg; cur; cur = cur->link) {
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000230 line_l += cur->lenght; /* previous allocated */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000231 if (prev != cur)
232 prev = prev->link;
Glenn L McGrath99825962003-10-09 11:06:45 +0000233 }
Eric Andersen92a61c12000-09-22 20:01:23 +0000234
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000235 while (!eof_stdin_detected) {
236 c = getchar();
237 if (c == EOF) {
238 eof_stdin_detected++;
Mark Whitleye2e2c292000-11-14 22:43:21 +0000239 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000240 if (eof_str_detected)
241 continue;
242 if (c == EOF || ISSPACE(c)) {
243 if (s == NULL)
244 continue;
245 c = EOF;
Glenn L McGrath61796942003-10-10 12:10:18 +0000246 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000247 if (s == NULL)
248 s = p = buf;
249 if ((p - buf) >= mc)
250 bb_error_msg_and_die("argument line too long");
251 *p++ = c == EOF ? 0 : c;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000252 if (c == EOF) { /* word's delimiter or EOF detected */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000253 /* word loaded */
254 if (eof_str) {
255 eof_str_detected = strcmp(s, eof_str) == 0;
256 }
257 if (!eof_str_detected) {
258 size_t lenght = (p - buf);
259
260 cur = xmalloc(sizeof(xlist_t) + lenght);
261 cur->data = memcpy(cur + 1, s, lenght);
262 cur->lenght = lenght;
263 cur->link = NULL;
264 if (prev == NULL) {
265 list_arg = cur;
266 } else {
267 prev->link = cur;
268 }
269 prev = cur;
270 line_l += lenght;
271 if (line_l > mc) {
272 /* stop memory usage :-) */
273 break;
274 }
275 s = NULL;
276 }
277 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000278 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000279 return list_arg;
Eric Andersen92a61c12000-09-22 20:01:23 +0000280}
Eric Andersen252183e2003-10-31 08:19:44 +0000281#endif /* CONFIG_FEATURE_XARGS_SUPPORT_QUOTES */
Glenn L McGrath61796942003-10-10 12:10:18 +0000282
283
284#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
285/* Prompt the user for a response, and
286 if the user responds affirmatively, return true;
287 otherwise, return false. Used "/dev/tty", not stdin. */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000288static int xargs_ask_confirmation(void)
Glenn L McGrath61796942003-10-10 12:10:18 +0000289{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000290 static FILE *tty_stream;
291 int c, savec;
Glenn L McGrath61796942003-10-10 12:10:18 +0000292
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000293 if (!tty_stream) {
Rob Landleyd921b2e2006-08-03 15:41:12 +0000294 tty_stream = xfopen(CURRENT_TTY, "r");
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000295 /* pranoidal security by vodz */
296 fcntl(fileno(tty_stream), F_SETFD, FD_CLOEXEC);
297 }
298 fputs(" ?...", stderr);
299 fflush(stderr);
300 c = savec = getc(tty_stream);
301 while (c != EOF && c != '\n')
302 c = getc(tty_stream);
303 if (savec == 'y' || savec == 'Y')
304 return 1;
305 return 0;
Glenn L McGrath61796942003-10-10 12:10:18 +0000306}
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000307
Glenn L McGrath61796942003-10-10 12:10:18 +0000308# define OPT_INC_P 1
309#else
310# define OPT_INC_P 0
311# define xargs_ask_confirmation() 1
Eric Andersen252183e2003-10-31 08:19:44 +0000312#endif /* CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION */
Glenn L McGrath61796942003-10-10 12:10:18 +0000313
314#ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
315# define OPT_INC_X 1
316#else
317# define OPT_INC_X 0
318#endif
319
320#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000321static xlist_t *process0_stdin(xlist_t * list_arg, const char *eof_str ATTRIBUTE_UNUSED,
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000322 size_t mc, char *buf)
Glenn L McGrath61796942003-10-10 12:10:18 +0000323{
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000324 int c; /* current char */
325 char *s = NULL; /* start word */
326 char *p = NULL; /* pointer to end word */
327 size_t line_l = 0; /* size loaded args line */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000328 xlist_t *cur;
329 xlist_t *prev;
Glenn L McGrath61796942003-10-10 12:10:18 +0000330
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000331 for (prev = cur = list_arg; cur; cur = cur->link) {
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000332 line_l += cur->lenght; /* previous allocated */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000333 if (prev != cur)
334 prev = prev->link;
Glenn L McGrath61796942003-10-10 12:10:18 +0000335 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000336
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000337 while (!eof_stdin_detected) {
338 c = getchar();
339 if (c == EOF) {
340 eof_stdin_detected++;
341 if (s == NULL)
342 break;
343 c = 0;
Glenn L McGrath61796942003-10-10 12:10:18 +0000344 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000345 if (s == NULL)
346 s = p = buf;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000347 if ((size_t)(p - buf) >= mc)
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000348 bb_error_msg_and_die("argument line too long");
349 *p++ = c;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000350 if (c == 0) { /* word's delimiter or EOF detected */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000351 /* word loaded */
352 size_t lenght = (p - buf);
353
354 cur = xmalloc(sizeof(xlist_t) + lenght);
355 cur->data = memcpy(cur + 1, s, lenght);
356 cur->lenght = lenght;
357 cur->link = NULL;
358 if (prev == NULL) {
359 list_arg = cur;
360 } else {
361 prev->link = cur;
362 }
363 prev = cur;
364 line_l += lenght;
365 if (line_l > mc) {
366 /* stop memory usage :-) */
367 break;
368 }
369 s = NULL;
Glenn L McGrath61796942003-10-10 12:10:18 +0000370 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000371 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000372 return list_arg;
Glenn L McGrath61796942003-10-10 12:10:18 +0000373}
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000374
Glenn L McGrath61796942003-10-10 12:10:18 +0000375# define READ_ARGS(l, e, nmc, mc) (*read_args)(l, e, nmc, mc)
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000376# define OPT_INC_0 1 /* future use */
Glenn L McGrath61796942003-10-10 12:10:18 +0000377#else
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000378# define OPT_INC_0 0 /* future use */
Glenn L McGrath61796942003-10-10 12:10:18 +0000379# define READ_ARGS(l, e, nmc, mc) process_stdin(l, e, nmc, mc)
Eric Andersen252183e2003-10-31 08:19:44 +0000380#endif /* CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM */
Glenn L McGrath61796942003-10-10 12:10:18 +0000381
382
383#define OPT_VERBOSE (1<<0)
384#define OPT_NO_EMPTY (1<<1)
385#define OPT_UPTO_NUMBER (1<<2)
386#define OPT_UPTO_SIZE (1<<3)
387#define OPT_EOF_STRING (1<<4)
388#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
389#define OPT_INTERACTIVE (1<<5)
390#else
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000391#define OPT_INTERACTIVE (0) /* require for algorithm &| */
Glenn L McGrath61796942003-10-10 12:10:18 +0000392#endif
393#define OPT_TERMINATE (1<<(5+OPT_INC_P))
394#define OPT_ZEROTERM (1<<(5+OPT_INC_P+OPT_INC_X))
395/* next future
396#define OPT_NEXT_OTHER (1<<(5+OPT_INC_P+OPT_INC_X+OPT_INC_0))
397*/
398
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000399int xargs_main(int argc, char **argv)
Glenn L McGrath61796942003-10-10 12:10:18 +0000400{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000401 char **args;
402 int i, a, n;
403 xlist_t *list = NULL;
404 xlist_t *cur;
405 int child_error = 0;
406 char *max_args, *max_chars;
407 int n_max_arg;
408 size_t n_chars = 0;
409 long orig_arg_max;
410 const char *eof_str = "_";
411 unsigned long opt;
412 size_t n_max_chars;
413
Glenn L McGrath61796942003-10-10 12:10:18 +0000414#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
Eric Andersen252183e2003-10-31 08:19:44 +0000415 xlist_t *(*read_args) (xlist_t *, const char *, size_t, char *) = process_stdin;
Glenn L McGrath61796942003-10-10 12:10:18 +0000416#endif
417
418#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000419 bb_opt_complementally = "pt";
Glenn L McGrath61796942003-10-10 12:10:18 +0000420#endif
421
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000422 opt = bb_getopt_ulflags(argc, argv, "+trn:s:e::"
Glenn L McGrath61796942003-10-10 12:10:18 +0000423#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
Eric Andersen252183e2003-10-31 08:19:44 +0000424 "p"
Glenn L McGrath61796942003-10-10 12:10:18 +0000425#endif
426#ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
Eric Andersen252183e2003-10-31 08:19:44 +0000427 "x"
Glenn L McGrath61796942003-10-10 12:10:18 +0000428#endif
429#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
Eric Andersen252183e2003-10-31 08:19:44 +0000430 "0"
Glenn L McGrath61796942003-10-10 12:10:18 +0000431#endif
Eric Andersen252183e2003-10-31 08:19:44 +0000432 ,&max_args, &max_chars, &eof_str);
Glenn L McGrath61796942003-10-10 12:10:18 +0000433
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000434 a = argc - optind;
435 argv += optind;
436 if (a == 0) {
437 /* default behavior is to echo all the filenames */
438 *argv = "echo";
439 a++;
Glenn L McGrath61796942003-10-10 12:10:18 +0000440 }
441
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000442 orig_arg_max = ARG_MAX;
443 if (orig_arg_max == -1)
444 orig_arg_max = LONG_MAX;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000445 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048. */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000446 if ((opt & OPT_UPTO_SIZE)) {
447 n_max_chars = bb_xgetularg10_bnd(max_chars, 1, orig_arg_max);
448 for (i = 0; i < a; i++) {
449 n_chars += strlen(*argv) + 1;
Glenn L McGrath61796942003-10-10 12:10:18 +0000450 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000451 if (n_max_chars < n_chars) {
Eric Andersen252183e2003-10-31 08:19:44 +0000452 bb_error_msg_and_die("can not fit single argument within argument list size limit");
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000453 }
454 n_max_chars -= n_chars;
455 } else {
456 /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
457 have it at 1 meg). Things will work fine with a large ARG_MAX but it
458 will probably hurt the system more than it needs to; an array of this
459 size is allocated. */
460 if (orig_arg_max > 20 * 1024)
461 orig_arg_max = 20 * 1024;
462 n_max_chars = orig_arg_max;
Glenn L McGrath61796942003-10-10 12:10:18 +0000463 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000464 max_chars = xmalloc(n_max_chars);
465
466 if ((opt & OPT_UPTO_NUMBER)) {
467 n_max_arg = bb_xgetularg10_bnd(max_args, 1, INT_MAX);
468 } else {
469 n_max_arg = n_max_chars;
Glenn L McGrath61796942003-10-10 12:10:18 +0000470 }
471
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000472#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
473 if (opt & OPT_ZEROTERM)
474 read_args = process0_stdin;
Glenn L McGrath61796942003-10-10 12:10:18 +0000475#endif
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000476
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000477 while ((list = READ_ARGS(list, eof_str, n_max_chars, max_chars)) != NULL ||
478 (opt & OPT_NO_EMPTY) == 0)
Eric Andersen252183e2003-10-31 08:19:44 +0000479 {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000480 opt |= OPT_NO_EMPTY;
481 n = 0;
482 n_chars = 0;
483#ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
484 for (cur = list; cur;) {
485 n_chars += cur->lenght;
486 n++;
487 cur = cur->link;
488 if (n_chars > n_max_chars || (n == n_max_arg && cur)) {
489 if (opt & OPT_TERMINATE)
490 bb_error_msg_and_die("argument list too long");
491 break;
492 }
493 }
494#else
495 for (cur = list; cur; cur = cur->link) {
496 n_chars += cur->lenght;
497 n++;
498 if (n_chars > n_max_chars || n == n_max_arg) {
499 break;
500 }
501 }
Eric Andersen252183e2003-10-31 08:19:44 +0000502#endif /* CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000503
504 /* allocating pointers for execvp:
505 a*arg, n*arg from stdin, NULL */
Rob Landley081e3842006-08-03 20:07:35 +0000506 args = xzalloc((n + a + 1) * sizeof(char *));
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000507
508 /* Store the command to be executed
509 (taken from the command line) */
510 for (i = 0; i < a; i++)
511 args[i] = argv[i];
512 /* (taken from stdin) */
513 for (cur = list; n; cur = cur->link) {
514 args[i++] = cur->data;
515 n--;
516 }
517
518 if ((opt & (OPT_INTERACTIVE | OPT_VERBOSE))) {
519 for (i = 0; args[i]; i++) {
520 if (i)
521 fputc(' ', stderr);
522 fputs(args[i], stderr);
523 }
524 if ((opt & OPT_INTERACTIVE) == 0)
525 fputc('\n', stderr);
526 }
527 if ((opt & OPT_INTERACTIVE) == 0 || xargs_ask_confirmation() != 0) {
528 child_error = xargs_exec(args);
529 }
530
531 /* clean up */
532 for (i = a; args[i]; i++) {
533 cur = list;
534 list = list->link;
535 free(cur);
536 }
537 free(args);
538 if (child_error > 0 && child_error != 123) {
539 break;
540 }
541 }
542#ifdef CONFIG_FEATURE_CLEAN_UP
543 free(max_chars);
544#endif
545 return child_error;
Glenn L McGrath61796942003-10-10 12:10:18 +0000546}
547
548
549#ifdef TEST
550
551const char *bb_applet_name = "debug stuff usage";
552
553void bb_show_usage(void)
554{
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000555 fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
Eric Andersen252183e2003-10-31 08:19:44 +0000556 bb_applet_name);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000557 exit(1);
Glenn L McGrath61796942003-10-10 12:10:18 +0000558}
559
560int main(int argc, char **argv)
561{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000562 return xargs_main(argc, argv);
Glenn L McGrath61796942003-10-10 12:10:18 +0000563}
Eric Andersen252183e2003-10-31 08:19:44 +0000564#endif /* TEST */