blob: c3a892695fd801393e75bcffdc3999b7a442f376 [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 Andersen5b176932000-09-22 20:22:28 +000021#include <stdio.h>
Mark Whitleye2e2c292000-11-14 22:43:21 +000022#include <stdlib.h>
Glenn L McGrathadd3ead2003-10-04 14:44:27 +000023#include <string.h>
Glenn L McGrathf57674e2002-11-10 21:47:17 +000024#include <unistd.h>
25#include <getopt.h>
26#include <errno.h>
Glenn L McGrath61796942003-10-10 12:10:18 +000027#include <fcntl.h>
Glenn L McGrathf57674e2002-11-10 21:47:17 +000028#include <sys/types.h>
29#include <sys/wait.h>
Eric Andersen92a61c12000-09-22 20:01:23 +000030
Glenn L McGrath61796942003-10-10 12:10:18 +000031/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
32 We try to make it as large as possible. */
33#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
34#define ARG_MAX sysconf (_SC_ARG_MAX)
35#endif
36#ifndef ARG_MAX
37#define ARG_MAX 470
38#endif
39
40
41#ifdef TEST
42# ifndef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
43# define CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
44# endif
45# ifndef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
46# define CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
47# endif
48# ifndef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
49# define CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
50# endif
51# ifndef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
52# define CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
53# endif
54#endif
55
Glenn L McGrathf57674e2002-11-10 21:47:17 +000056/*
57 This function have special algorithm.
58 Don`t use fork and include to main!
59*/
Glenn L McGrath09c295a2003-10-30 22:47:16 +000060static int xargs_exec(char *const *args)
Glenn L McGrathf57674e2002-11-10 21:47:17 +000061{
Glenn L McGrath09c295a2003-10-30 22:47:16 +000062 pid_t p;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +000063 volatile int exec_errno = 0; /* shared vfork stack */
Glenn L McGrath61796942003-10-10 12:10:18 +000064
Glenn L McGrath09c295a2003-10-30 22:47:16 +000065 if ((p = vfork()) >= 0) {
66 if (p == 0) {
67 /* vfork -- child */
68 execvp(args[0], args);
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +000069 exec_errno = errno; /* set error to shared stack */
Glenn L McGrath09c295a2003-10-30 22:47:16 +000070 _exit(1);
71 } else {
72 /* vfork -- parent */
73 int status;
74
75 while (wait(&status) == (pid_t) - 1)
76 if (errno != EINTR)
77 break;
78 if (exec_errno) {
79 errno = exec_errno;
80 bb_perror_msg("%s", args[0]);
81 return exec_errno == ENOENT ? 127 : 126;
82 } else {
83 if (WEXITSTATUS(status) == 255) {
Eric Andersen252183e2003-10-31 08:19:44 +000084 bb_error_msg("%s: exited with status 255; aborting", args[0]);
Glenn L McGrath09c295a2003-10-30 22:47:16 +000085 return 124;
86 }
87 if (WIFSTOPPED(status)) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +000088 bb_error_msg("%s: stopped by signal %d",
Eric Andersen252183e2003-10-31 08:19:44 +000089 args[0], WSTOPSIG(status));
Glenn L McGrath09c295a2003-10-30 22:47:16 +000090 return 125;
91 }
92 if (WIFSIGNALED(status)) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +000093 bb_error_msg("%s: terminated by signal %d",
Eric Andersen252183e2003-10-31 08:19:44 +000094 args[0], WTERMSIG(status));
Glenn L McGrath09c295a2003-10-30 22:47:16 +000095 return 125;
96 }
97 if (WEXITSTATUS(status) != 0)
98 return 123;
99 return 0;
100 }
101 }
Glenn L McGrath99825962003-10-09 11:06:45 +0000102 } else {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000103 bb_perror_msg_and_die("vfork");
Glenn L McGrath61796942003-10-10 12:10:18 +0000104 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000105}
Glenn L McGrath99825962003-10-09 11:06:45 +0000106
Glenn L McGrath61796942003-10-10 12:10:18 +0000107
108typedef struct xlist_s {
109 char *data;
110 size_t lenght;
111 struct xlist_s *link;
112} xlist_t;
113
114static int eof_stdin_detected;
115
116#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
117#define ISSPACE(c) (ISBLANK (c) || (c) == '\n' || (c) == '\r' \
118 || (c) == '\f' || (c) == '\v')
119
120#ifdef CONFIG_FEATURE_XARGS_SUPPORT_QUOTES
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000121static xlist_t *process_stdin(xlist_t * list_arg,
Eric Andersen252183e2003-10-31 08:19:44 +0000122 const char *eof_str, size_t mc, char *buf)
Glenn L McGrath61796942003-10-10 12:10:18 +0000123{
124#define NORM 0
125#define QUOTE 1
126#define BACKSLASH 2
127#define SPACE 4
128
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000129 char *s = NULL; /* start word */
130 char *p = NULL; /* pointer to end word */
131 char q = 0; /* quote char */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000132 char state = NORM;
133 char eof_str_detected = 0;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000134 size_t line_l = 0; /* size loaded args line */
135 int c; /* current char */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000136 xlist_t *cur;
137 xlist_t *prev;
Glenn L McGrath61796942003-10-10 12:10:18 +0000138
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000139 for (prev = cur = list_arg; cur; cur = cur->link) {
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000140 line_l += cur->lenght; /* previous allocated */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000141 if (prev != cur)
142 prev = prev->link;
Glenn L McGrath61796942003-10-10 12:10:18 +0000143 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000144
145 while (!eof_stdin_detected) {
146 c = getchar();
147 if (c == EOF) {
148 eof_stdin_detected++;
149 if (s)
150 goto unexpected_eof;
151 break;
Glenn L McGrath61796942003-10-10 12:10:18 +0000152 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000153 if (eof_str_detected)
154 continue;
155 if (state == BACKSLASH) {
156 state = NORM;
157 goto set;
158 } else if (state == QUOTE) {
159 if (c == q) {
160 q = 0;
161 state = NORM;
162 } else {
163 goto set;
164 }
Eric Andersen252183e2003-10-31 08:19:44 +0000165 } else { /* if(state == NORM) */
Glenn L McGrath61796942003-10-10 12:10:18 +0000166
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000167 if (ISSPACE(c)) {
168 if (s) {
Eric Andersen252183e2003-10-31 08:19:44 +0000169unexpected_eof:
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000170 state = SPACE;
171 c = 0;
172 goto set;
173 }
174 } else {
175 if (s == NULL)
176 s = p = buf;
177 if (c == '\\') {
178 state = BACKSLASH;
179 } else if (c == '\'' || c == '"') {
180 q = c;
181 state = QUOTE;
182 } else {
Eric Andersen252183e2003-10-31 08:19:44 +0000183set:
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000184 if ((size_t)(p - buf) >= mc)
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000185 bb_error_msg_and_die("argument line too long");
186 *p++ = c;
187 }
188 }
189 }
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000190 if (state == SPACE) { /* word's delimiter or EOF detected */
Eric Andersen252183e2003-10-31 08:19:44 +0000191 if (q) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000192 bb_error_msg_and_die("unmatched %s quote",
Eric Andersen252183e2003-10-31 08:19:44 +0000193 q == '\'' ? "single" : "double");
194 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000195 /* word loaded */
196 if (eof_str) {
197 eof_str_detected = strcmp(s, eof_str) == 0;
198 }
199 if (!eof_str_detected) {
200 size_t lenght = (p - buf);
201
202 cur = xmalloc(sizeof(xlist_t) + lenght);
203 cur->data = memcpy(cur + 1, s, lenght);
204 cur->lenght = lenght;
205 cur->link = NULL;
206 if (prev == NULL) {
207 list_arg = cur;
208 } else {
209 prev->link = cur;
210 }
211 prev = cur;
212 line_l += lenght;
213 if (line_l > mc) {
214 /* stop memory usage :-) */
215 break;
216 }
217 }
218 s = NULL;
219 state = NORM;
220 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000221 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000222 return list_arg;
Glenn L McGrathf57674e2002-11-10 21:47:17 +0000223}
Glenn L McGrath61796942003-10-10 12:10:18 +0000224#else
Eric Andersen252183e2003-10-31 08:19:44 +0000225/* The variant does not support single quotes, double quotes or backslash */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000226static xlist_t *process_stdin(xlist_t * list_arg,
Eric Andersen252183e2003-10-31 08:19:44 +0000227 const char *eof_str, size_t mc, char *buf)
Eric Andersen92a61c12000-09-22 20:01:23 +0000228{
Eric Andersen92a61c12000-09-22 20:01:23 +0000229
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000230 int c; /* current char */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000231 int eof_str_detected = 0;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000232 char *s = NULL; /* start word */
233 char *p = NULL; /* pointer to end word */
234 size_t line_l = 0; /* size loaded args line */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000235 xlist_t *cur;
236 xlist_t *prev;
Glenn L McGrathadd3ead2003-10-04 14:44:27 +0000237
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000238 for (prev = cur = list_arg; cur; cur = cur->link) {
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000239 line_l += cur->lenght; /* previous allocated */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000240 if (prev != cur)
241 prev = prev->link;
Glenn L McGrath99825962003-10-09 11:06:45 +0000242 }
Eric Andersen92a61c12000-09-22 20:01:23 +0000243
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000244 while (!eof_stdin_detected) {
245 c = getchar();
246 if (c == EOF) {
247 eof_stdin_detected++;
Mark Whitleye2e2c292000-11-14 22:43:21 +0000248 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000249 if (eof_str_detected)
250 continue;
251 if (c == EOF || ISSPACE(c)) {
252 if (s == NULL)
253 continue;
254 c = EOF;
Glenn L McGrath61796942003-10-10 12:10:18 +0000255 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000256 if (s == NULL)
257 s = p = buf;
258 if ((p - buf) >= mc)
259 bb_error_msg_and_die("argument line too long");
260 *p++ = c == EOF ? 0 : c;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000261 if (c == EOF) { /* word's delimiter or EOF detected */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000262 /* word loaded */
263 if (eof_str) {
264 eof_str_detected = strcmp(s, eof_str) == 0;
265 }
266 if (!eof_str_detected) {
267 size_t lenght = (p - buf);
268
269 cur = xmalloc(sizeof(xlist_t) + lenght);
270 cur->data = memcpy(cur + 1, s, lenght);
271 cur->lenght = lenght;
272 cur->link = NULL;
273 if (prev == NULL) {
274 list_arg = cur;
275 } else {
276 prev->link = cur;
277 }
278 prev = cur;
279 line_l += lenght;
280 if (line_l > mc) {
281 /* stop memory usage :-) */
282 break;
283 }
284 s = NULL;
285 }
286 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000287 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000288 return list_arg;
Eric Andersen92a61c12000-09-22 20:01:23 +0000289}
Eric Andersen252183e2003-10-31 08:19:44 +0000290#endif /* CONFIG_FEATURE_XARGS_SUPPORT_QUOTES */
Glenn L McGrath61796942003-10-10 12:10:18 +0000291
292
293#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
294/* Prompt the user for a response, and
295 if the user responds affirmatively, return true;
296 otherwise, return false. Used "/dev/tty", not stdin. */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000297static int xargs_ask_confirmation(void)
Glenn L McGrath61796942003-10-10 12:10:18 +0000298{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000299 static FILE *tty_stream;
300 int c, savec;
Glenn L McGrath61796942003-10-10 12:10:18 +0000301
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000302 if (!tty_stream) {
Bernhard Reutner-Fischer95a040f2006-05-27 09:36:43 +0000303 tty_stream = bb_xfopen(CURRENT_TTY, "r");
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000304 /* pranoidal security by vodz */
305 fcntl(fileno(tty_stream), F_SETFD, FD_CLOEXEC);
306 }
307 fputs(" ?...", stderr);
308 fflush(stderr);
309 c = savec = getc(tty_stream);
310 while (c != EOF && c != '\n')
311 c = getc(tty_stream);
312 if (savec == 'y' || savec == 'Y')
313 return 1;
314 return 0;
Glenn L McGrath61796942003-10-10 12:10:18 +0000315}
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000316
Glenn L McGrath61796942003-10-10 12:10:18 +0000317# define OPT_INC_P 1
318#else
319# define OPT_INC_P 0
320# define xargs_ask_confirmation() 1
Eric Andersen252183e2003-10-31 08:19:44 +0000321#endif /* CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION */
Glenn L McGrath61796942003-10-10 12:10:18 +0000322
323#ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
324# define OPT_INC_X 1
325#else
326# define OPT_INC_X 0
327#endif
328
329#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000330static xlist_t *process0_stdin(xlist_t * list_arg, const char *eof_str ATTRIBUTE_UNUSED,
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000331 size_t mc, char *buf)
Glenn L McGrath61796942003-10-10 12:10:18 +0000332{
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000333 int c; /* current char */
334 char *s = NULL; /* start word */
335 char *p = NULL; /* pointer to end word */
336 size_t line_l = 0; /* size loaded args line */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000337 xlist_t *cur;
338 xlist_t *prev;
Glenn L McGrath61796942003-10-10 12:10:18 +0000339
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000340 for (prev = cur = list_arg; cur; cur = cur->link) {
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000341 line_l += cur->lenght; /* previous allocated */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000342 if (prev != cur)
343 prev = prev->link;
Glenn L McGrath61796942003-10-10 12:10:18 +0000344 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000345
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000346 while (!eof_stdin_detected) {
347 c = getchar();
348 if (c == EOF) {
349 eof_stdin_detected++;
350 if (s == NULL)
351 break;
352 c = 0;
Glenn L McGrath61796942003-10-10 12:10:18 +0000353 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000354 if (s == NULL)
355 s = p = buf;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000356 if ((size_t)(p - buf) >= mc)
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000357 bb_error_msg_and_die("argument line too long");
358 *p++ = c;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000359 if (c == 0) { /* word's delimiter or EOF detected */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000360 /* word loaded */
361 size_t lenght = (p - buf);
362
363 cur = xmalloc(sizeof(xlist_t) + lenght);
364 cur->data = memcpy(cur + 1, s, lenght);
365 cur->lenght = lenght;
366 cur->link = NULL;
367 if (prev == NULL) {
368 list_arg = cur;
369 } else {
370 prev->link = cur;
371 }
372 prev = cur;
373 line_l += lenght;
374 if (line_l > mc) {
375 /* stop memory usage :-) */
376 break;
377 }
378 s = NULL;
Glenn L McGrath61796942003-10-10 12:10:18 +0000379 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000380 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000381 return list_arg;
Glenn L McGrath61796942003-10-10 12:10:18 +0000382}
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000383
Glenn L McGrath61796942003-10-10 12:10:18 +0000384# define READ_ARGS(l, e, nmc, mc) (*read_args)(l, e, nmc, mc)
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000385# define OPT_INC_0 1 /* future use */
Glenn L McGrath61796942003-10-10 12:10:18 +0000386#else
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000387# define OPT_INC_0 0 /* future use */
Glenn L McGrath61796942003-10-10 12:10:18 +0000388# define READ_ARGS(l, e, nmc, mc) process_stdin(l, e, nmc, mc)
Eric Andersen252183e2003-10-31 08:19:44 +0000389#endif /* CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM */
Glenn L McGrath61796942003-10-10 12:10:18 +0000390
391
392#define OPT_VERBOSE (1<<0)
393#define OPT_NO_EMPTY (1<<1)
394#define OPT_UPTO_NUMBER (1<<2)
395#define OPT_UPTO_SIZE (1<<3)
396#define OPT_EOF_STRING (1<<4)
397#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
398#define OPT_INTERACTIVE (1<<5)
399#else
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000400#define OPT_INTERACTIVE (0) /* require for algorithm &| */
Glenn L McGrath61796942003-10-10 12:10:18 +0000401#endif
402#define OPT_TERMINATE (1<<(5+OPT_INC_P))
403#define OPT_ZEROTERM (1<<(5+OPT_INC_P+OPT_INC_X))
404/* next future
405#define OPT_NEXT_OTHER (1<<(5+OPT_INC_P+OPT_INC_X+OPT_INC_0))
406*/
407
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000408int xargs_main(int argc, char **argv)
Glenn L McGrath61796942003-10-10 12:10:18 +0000409{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000410 char **args;
411 int i, a, n;
412 xlist_t *list = NULL;
413 xlist_t *cur;
414 int child_error = 0;
415 char *max_args, *max_chars;
416 int n_max_arg;
417 size_t n_chars = 0;
418 long orig_arg_max;
419 const char *eof_str = "_";
420 unsigned long opt;
421 size_t n_max_chars;
422
Glenn L McGrath61796942003-10-10 12:10:18 +0000423#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
Eric Andersen252183e2003-10-31 08:19:44 +0000424 xlist_t *(*read_args) (xlist_t *, const char *, size_t, char *) = process_stdin;
Glenn L McGrath61796942003-10-10 12:10:18 +0000425#endif
426
427#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000428 bb_opt_complementally = "pt";
Glenn L McGrath61796942003-10-10 12:10:18 +0000429#endif
430
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000431 opt = bb_getopt_ulflags(argc, argv, "+trn:s:e::"
Glenn L McGrath61796942003-10-10 12:10:18 +0000432#ifdef CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION
Eric Andersen252183e2003-10-31 08:19:44 +0000433 "p"
Glenn L McGrath61796942003-10-10 12:10:18 +0000434#endif
435#ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
Eric Andersen252183e2003-10-31 08:19:44 +0000436 "x"
Glenn L McGrath61796942003-10-10 12:10:18 +0000437#endif
438#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
Eric Andersen252183e2003-10-31 08:19:44 +0000439 "0"
Glenn L McGrath61796942003-10-10 12:10:18 +0000440#endif
Eric Andersen252183e2003-10-31 08:19:44 +0000441 ,&max_args, &max_chars, &eof_str);
Glenn L McGrath61796942003-10-10 12:10:18 +0000442
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000443 a = argc - optind;
444 argv += optind;
445 if (a == 0) {
446 /* default behavior is to echo all the filenames */
447 *argv = "echo";
448 a++;
Glenn L McGrath61796942003-10-10 12:10:18 +0000449 }
450
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000451 orig_arg_max = ARG_MAX;
452 if (orig_arg_max == -1)
453 orig_arg_max = LONG_MAX;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000454 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048. */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000455 if ((opt & OPT_UPTO_SIZE)) {
456 n_max_chars = bb_xgetularg10_bnd(max_chars, 1, orig_arg_max);
457 for (i = 0; i < a; i++) {
458 n_chars += strlen(*argv) + 1;
Glenn L McGrath61796942003-10-10 12:10:18 +0000459 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000460 if (n_max_chars < n_chars) {
Eric Andersen252183e2003-10-31 08:19:44 +0000461 bb_error_msg_and_die("can not fit single argument within argument list size limit");
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000462 }
463 n_max_chars -= n_chars;
464 } else {
465 /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
466 have it at 1 meg). Things will work fine with a large ARG_MAX but it
467 will probably hurt the system more than it needs to; an array of this
468 size is allocated. */
469 if (orig_arg_max > 20 * 1024)
470 orig_arg_max = 20 * 1024;
471 n_max_chars = orig_arg_max;
Glenn L McGrath61796942003-10-10 12:10:18 +0000472 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000473 max_chars = xmalloc(n_max_chars);
474
475 if ((opt & OPT_UPTO_NUMBER)) {
476 n_max_arg = bb_xgetularg10_bnd(max_args, 1, INT_MAX);
477 } else {
478 n_max_arg = n_max_chars;
Glenn L McGrath61796942003-10-10 12:10:18 +0000479 }
480
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000481#ifdef CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM
482 if (opt & OPT_ZEROTERM)
483 read_args = process0_stdin;
Glenn L McGrath61796942003-10-10 12:10:18 +0000484#endif
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000485
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000486 while ((list = READ_ARGS(list, eof_str, n_max_chars, max_chars)) != NULL ||
487 (opt & OPT_NO_EMPTY) == 0)
Eric Andersen252183e2003-10-31 08:19:44 +0000488 {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000489 opt |= OPT_NO_EMPTY;
490 n = 0;
491 n_chars = 0;
492#ifdef CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT
493 for (cur = list; cur;) {
494 n_chars += cur->lenght;
495 n++;
496 cur = cur->link;
497 if (n_chars > n_max_chars || (n == n_max_arg && cur)) {
498 if (opt & OPT_TERMINATE)
499 bb_error_msg_and_die("argument list too long");
500 break;
501 }
502 }
503#else
504 for (cur = list; cur; cur = cur->link) {
505 n_chars += cur->lenght;
506 n++;
507 if (n_chars > n_max_chars || n == n_max_arg) {
508 break;
509 }
510 }
Eric Andersen252183e2003-10-31 08:19:44 +0000511#endif /* CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000512
513 /* allocating pointers for execvp:
514 a*arg, n*arg from stdin, NULL */
515 args = xcalloc(n + a + 1, sizeof(char *));
516
517 /* Store the command to be executed
518 (taken from the command line) */
519 for (i = 0; i < a; i++)
520 args[i] = argv[i];
521 /* (taken from stdin) */
522 for (cur = list; n; cur = cur->link) {
523 args[i++] = cur->data;
524 n--;
525 }
526
527 if ((opt & (OPT_INTERACTIVE | OPT_VERBOSE))) {
528 for (i = 0; args[i]; i++) {
529 if (i)
530 fputc(' ', stderr);
531 fputs(args[i], stderr);
532 }
533 if ((opt & OPT_INTERACTIVE) == 0)
534 fputc('\n', stderr);
535 }
536 if ((opt & OPT_INTERACTIVE) == 0 || xargs_ask_confirmation() != 0) {
537 child_error = xargs_exec(args);
538 }
539
540 /* clean up */
541 for (i = a; args[i]; i++) {
542 cur = list;
543 list = list->link;
544 free(cur);
545 }
546 free(args);
547 if (child_error > 0 && child_error != 123) {
548 break;
549 }
550 }
551#ifdef CONFIG_FEATURE_CLEAN_UP
552 free(max_chars);
553#endif
554 return child_error;
Glenn L McGrath61796942003-10-10 12:10:18 +0000555}
556
557
558#ifdef TEST
559
560const char *bb_applet_name = "debug stuff usage";
561
562void bb_show_usage(void)
563{
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000564 fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
Eric Andersen252183e2003-10-31 08:19:44 +0000565 bb_applet_name);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000566 exit(1);
Glenn L McGrath61796942003-10-10 12:10:18 +0000567}
568
569int main(int argc, char **argv)
570{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000571 return xargs_main(argc, argv);
Glenn L McGrath61796942003-10-10 12:10:18 +0000572}
Eric Andersen252183e2003-10-31 08:19:44 +0000573#endif /* TEST */