blob: a430e5f3d771bffd53d6a18dd1e5564a474f2f8d [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
Denis Vlasenko99912ca2007-04-10 15:43:37 +000022/* This is a NOEXEC applet. Be very careful! */
23
24
Glenn L McGrath61796942003-10-10 12:10:18 +000025/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
26 We try to make it as large as possible. */
27#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
28#define ARG_MAX sysconf (_SC_ARG_MAX)
29#endif
30#ifndef ARG_MAX
31#define ARG_MAX 470
32#endif
33
34
35#ifdef TEST
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000036# ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
37# define ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 1
Glenn L McGrath61796942003-10-10 12:10:18 +000038# endif
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000039# ifndef ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
40# define ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 1
Glenn L McGrath61796942003-10-10 12:10:18 +000041# endif
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000042# ifndef ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
43# define ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT 1
Glenn L McGrath61796942003-10-10 12:10:18 +000044# endif
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000045# ifndef ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
46# define ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 1
Glenn L McGrath61796942003-10-10 12:10:18 +000047# endif
48#endif
49
Glenn L McGrathf57674e2002-11-10 21:47:17 +000050/*
Denis Vlasenko6248a732006-09-29 08:20:30 +000051 This function has special algorithm.
52 Don't use fork and include to main!
Glenn L McGrathf57674e2002-11-10 21:47:17 +000053*/
Denis Vlasenkocd7001f2007-04-09 21:32:30 +000054static int xargs_exec(char **args)
Glenn L McGrathf57674e2002-11-10 21:47:17 +000055{
Denis Vlasenko6248a732006-09-29 08:20:30 +000056 int status;
Glenn L McGrath61796942003-10-10 12:10:18 +000057
Denis Vlasenkocd7001f2007-04-09 21:32:30 +000058 status = spawn_and_wait(args);
59 if (status < 0) {
Denis Vlasenko6248a732006-09-29 08:20:30 +000060 bb_perror_msg("%s", args[0]);
Denis Vlasenkocd7001f2007-04-09 21:32:30 +000061 return errno == ENOENT ? 127 : 126;
Denis Vlasenko6248a732006-09-29 08:20:30 +000062 }
Denis Vlasenkocd7001f2007-04-09 21:32:30 +000063 if (status == 255) {
Denis Vlasenko6248a732006-09-29 08:20:30 +000064 bb_error_msg("%s: exited with status 255; aborting", args[0]);
65 return 124;
66 }
Denis Vlasenkocd7001f2007-04-09 21:32:30 +000067/* Huh? I think we won't see this, ever. We don't wait with WUNTRACED!
Denis Vlasenko6248a732006-09-29 08:20:30 +000068 if (WIFSTOPPED(status)) {
69 bb_error_msg("%s: stopped by signal %d",
70 args[0], WSTOPSIG(status));
71 return 125;
72 }
Denis Vlasenkocd7001f2007-04-09 21:32:30 +000073*/
74 if (status >= 1000) {
Denis Vlasenko6248a732006-09-29 08:20:30 +000075 bb_error_msg("%s: terminated by signal %d",
Denis Vlasenkocd7001f2007-04-09 21:32:30 +000076 args[0], status - 1000);
Denis Vlasenko6248a732006-09-29 08:20:30 +000077 return 125;
78 }
Denis Vlasenkocd7001f2007-04-09 21:32:30 +000079 if (status)
Denis Vlasenko6248a732006-09-29 08:20:30 +000080 return 123;
81 return 0;
Glenn L McGrath61796942003-10-10 12:10:18 +000082}
Glenn L McGrath99825962003-10-09 11:06:45 +000083
Glenn L McGrath61796942003-10-10 12:10:18 +000084
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000085typedef struct xlist_t {
Glenn L McGrath61796942003-10-10 12:10:18 +000086 char *data;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000087 size_t length;
88 struct xlist_t *link;
Glenn L McGrath61796942003-10-10 12:10:18 +000089} xlist_t;
90
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000091static smallint eof_stdin_detected;
Glenn L McGrath61796942003-10-10 12:10:18 +000092
93#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
Denis Vlasenko6248a732006-09-29 08:20:30 +000094#define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \
Glenn L McGrath61796942003-10-10 12:10:18 +000095 || (c) == '\f' || (c) == '\v')
96
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000097#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
98static xlist_t *process_stdin(xlist_t *list_arg,
Eric Andersen252183e2003-10-31 08:19:44 +000099 const char *eof_str, size_t mc, char *buf)
Glenn L McGrath61796942003-10-10 12:10:18 +0000100{
101#define NORM 0
102#define QUOTE 1
103#define BACKSLASH 2
104#define SPACE 4
105
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000106 char *s = NULL; /* start word */
107 char *p = NULL; /* pointer to end word */
108 char q = 0; /* quote char */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000109 char state = NORM;
110 char eof_str_detected = 0;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000111 size_t line_l = 0; /* size loaded args line */
112 int c; /* current char */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000113 xlist_t *cur;
114 xlist_t *prev;
Glenn L McGrath61796942003-10-10 12:10:18 +0000115
Denis Vlasenko89054962007-04-10 21:41:16 +0000116 prev = cur = list_arg;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000117 while (1) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000118 if (!cur) break;
Denis Vlasenko89054962007-04-10 21:41:16 +0000119 prev = cur;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000120 line_l += cur->length;
121 cur = cur->link;
Glenn L McGrath61796942003-10-10 12:10:18 +0000122 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000123
124 while (!eof_stdin_detected) {
125 c = getchar();
126 if (c == EOF) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000127 eof_stdin_detected = 1;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000128 if (s)
129 goto unexpected_eof;
130 break;
Glenn L McGrath61796942003-10-10 12:10:18 +0000131 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000132 if (eof_str_detected)
133 continue;
134 if (state == BACKSLASH) {
135 state = NORM;
136 goto set;
137 } else if (state == QUOTE) {
138 if (c == q) {
139 q = 0;
140 state = NORM;
141 } else {
142 goto set;
143 }
Denis Vlasenko51742f42007-04-12 00:32:05 +0000144 } else { /* if (state == NORM) */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000145 if (ISSPACE(c)) {
146 if (s) {
Eric Andersen252183e2003-10-31 08:19:44 +0000147unexpected_eof:
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000148 state = SPACE;
149 c = 0;
150 goto set;
151 }
152 } else {
153 if (s == NULL)
154 s = p = buf;
155 if (c == '\\') {
156 state = BACKSLASH;
157 } else if (c == '\'' || c == '"') {
158 q = c;
159 state = QUOTE;
160 } else {
Eric Andersen252183e2003-10-31 08:19:44 +0000161set:
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000162 if ((size_t)(p - buf) >= mc)
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000163 bb_error_msg_and_die("argument line too long");
164 *p++ = c;
165 }
166 }
167 }
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000168 if (state == SPACE) { /* word's delimiter or EOF detected */
Eric Andersen252183e2003-10-31 08:19:44 +0000169 if (q) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000170 bb_error_msg_and_die("unmatched %s quote",
Eric Andersen252183e2003-10-31 08:19:44 +0000171 q == '\'' ? "single" : "double");
172 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000173 /* word loaded */
174 if (eof_str) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000175 eof_str_detected = (strcmp(s, eof_str) == 0);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000176 }
177 if (!eof_str_detected) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000178 size_t length = (p - buf);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000179
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000180 cur = xzalloc(sizeof(xlist_t) + length);
181 cur->data = memcpy(cur + 1, s, length);
182 cur->length = length;
183 /*cur->link = NULL;*/
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000184 if (prev == NULL) {
185 list_arg = cur;
186 } else {
187 prev->link = cur;
188 }
189 prev = cur;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000190 line_l += length;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000191 if (line_l > mc) {
192 /* stop memory usage :-) */
193 break;
194 }
195 }
196 s = NULL;
197 state = NORM;
198 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000199 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000200 return list_arg;
Glenn L McGrathf57674e2002-11-10 21:47:17 +0000201}
Glenn L McGrath61796942003-10-10 12:10:18 +0000202#else
Eric Andersen252183e2003-10-31 08:19:44 +0000203/* The variant does not support single quotes, double quotes or backslash */
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000204static xlist_t *process_stdin(xlist_t *list_arg,
205 const char *eof_str, size_t mc, char *buf)
Eric Andersen92a61c12000-09-22 20:01:23 +0000206{
Eric Andersen92a61c12000-09-22 20:01:23 +0000207
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000208 int c; /* current char */
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000209 char eof_str_detected = 0;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000210 char *s = NULL; /* start word */
211 char *p = NULL; /* pointer to end word */
212 size_t line_l = 0; /* size loaded args line */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000213 xlist_t *cur;
214 xlist_t *prev;
Glenn L McGrathadd3ead2003-10-04 14:44:27 +0000215
Denis Vlasenko89054962007-04-10 21:41:16 +0000216 prev = cur = list_arg;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000217 while (1) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000218 if (!cur) break;
Denis Vlasenko89054962007-04-10 21:41:16 +0000219 prev = cur;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000220 line_l += cur->length;
221 cur = cur->link;
Glenn L McGrath99825962003-10-09 11:06:45 +0000222 }
Eric Andersen92a61c12000-09-22 20:01:23 +0000223
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000224 while (!eof_stdin_detected) {
225 c = getchar();
226 if (c == EOF) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000227 eof_stdin_detected = 1;
Mark Whitleye2e2c292000-11-14 22:43:21 +0000228 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000229 if (eof_str_detected)
230 continue;
231 if (c == EOF || ISSPACE(c)) {
232 if (s == NULL)
233 continue;
234 c = EOF;
Glenn L McGrath61796942003-10-10 12:10:18 +0000235 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000236 if (s == NULL)
237 s = p = buf;
238 if ((p - buf) >= mc)
239 bb_error_msg_and_die("argument line too long");
240 *p++ = c == EOF ? 0 : c;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000241 if (c == EOF) { /* word's delimiter or EOF detected */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000242 /* word loaded */
243 if (eof_str) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000244 eof_str_detected = (strcmp(s, eof_str) == 0);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000245 }
246 if (!eof_str_detected) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000247 size_t length = (p - buf);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000248
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000249 cur = xzalloc(sizeof(xlist_t) + length);
250 cur->data = memcpy(cur + 1, s, length);
251 cur->length = length;
252 /*cur->link = NULL;*/
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000253 if (prev == NULL) {
254 list_arg = cur;
255 } else {
256 prev->link = cur;
257 }
258 prev = cur;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000259 line_l += length;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000260 if (line_l > mc) {
261 /* stop memory usage :-) */
262 break;
263 }
264 s = NULL;
265 }
266 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000267 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000268 return list_arg;
Eric Andersen92a61c12000-09-22 20:01:23 +0000269}
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000270#endif /* FEATURE_XARGS_SUPPORT_QUOTES */
Glenn L McGrath61796942003-10-10 12:10:18 +0000271
272
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000273#if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
Glenn L McGrath61796942003-10-10 12:10:18 +0000274/* Prompt the user for a response, and
275 if the user responds affirmatively, return true;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000276 otherwise, return false. Uses "/dev/tty", not stdin. */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000277static int xargs_ask_confirmation(void)
Glenn L McGrath61796942003-10-10 12:10:18 +0000278{
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000279 FILE *tty_stream;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000280 int c, savec;
Glenn L McGrath61796942003-10-10 12:10:18 +0000281
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000282 tty_stream = xfopen(CURRENT_TTY, "r");
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000283 fputs(" ?...", stderr);
284 fflush(stderr);
285 c = savec = getc(tty_stream);
286 while (c != EOF && c != '\n')
287 c = getc(tty_stream);
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000288 fclose(tty_stream);
289 return (savec == 'y' || savec == 'Y');
Glenn L McGrath61796942003-10-10 12:10:18 +0000290}
Glenn L McGrath61796942003-10-10 12:10:18 +0000291#else
Glenn L McGrath61796942003-10-10 12:10:18 +0000292# define xargs_ask_confirmation() 1
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000293#endif /* FEATURE_XARGS_SUPPORT_CONFIRMATION */
Glenn L McGrath61796942003-10-10 12:10:18 +0000294
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000295#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
296static xlist_t *process0_stdin(xlist_t *list_arg,
297 const char *eof_str ATTRIBUTE_UNUSED, size_t mc, char *buf)
Glenn L McGrath61796942003-10-10 12:10:18 +0000298{
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000299 int c; /* current char */
300 char *s = NULL; /* start word */
301 char *p = NULL; /* pointer to end word */
302 size_t line_l = 0; /* size loaded args line */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000303 xlist_t *cur;
304 xlist_t *prev;
Glenn L McGrath61796942003-10-10 12:10:18 +0000305
Denis Vlasenko89054962007-04-10 21:41:16 +0000306 prev = cur = list_arg;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000307 while (1) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000308 if (!cur) break;
Denis Vlasenko89054962007-04-10 21:41:16 +0000309 prev = cur;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000310 line_l += cur->length;
311 cur = cur->link;
Glenn L McGrath61796942003-10-10 12:10:18 +0000312 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000313
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000314 while (!eof_stdin_detected) {
315 c = getchar();
316 if (c == EOF) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000317 eof_stdin_detected = 1;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000318 if (s == NULL)
319 break;
320 c = 0;
Glenn L McGrath61796942003-10-10 12:10:18 +0000321 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000322 if (s == NULL)
323 s = p = buf;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000324 if ((size_t)(p - buf) >= mc)
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000325 bb_error_msg_and_die("argument line too long");
326 *p++ = c;
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000327 if (c == 0) { /* word's delimiter or EOF detected */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000328 /* word loaded */
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000329 size_t length = (p - buf);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000330
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000331 cur = xzalloc(sizeof(xlist_t) + length);
332 cur->data = memcpy(cur + 1, s, length);
333 cur->length = length;
334 /*cur->link = NULL;*/
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000335 if (prev == NULL) {
336 list_arg = cur;
337 } else {
338 prev->link = cur;
339 }
340 prev = cur;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000341 line_l += length;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000342 if (line_l > mc) {
343 /* stop memory usage :-) */
344 break;
345 }
346 s = NULL;
Glenn L McGrath61796942003-10-10 12:10:18 +0000347 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000348 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000349 return list_arg;
Glenn L McGrath61796942003-10-10 12:10:18 +0000350}
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000351#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
Glenn L McGrath61796942003-10-10 12:10:18 +0000352
Denis Vlasenko6248a732006-09-29 08:20:30 +0000353/* Correct regardless of combination of CONFIG_xxx */
354enum {
355 OPTBIT_VERBOSE = 0,
356 OPTBIT_NO_EMPTY,
357 OPTBIT_UPTO_NUMBER,
358 OPTBIT_UPTO_SIZE,
359 OPTBIT_EOF_STRING,
360 USE_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
361 USE_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,)
362 USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,)
Glenn L McGrath61796942003-10-10 12:10:18 +0000363
Denis Vlasenko6248a732006-09-29 08:20:30 +0000364 OPT_VERBOSE = 1<<OPTBIT_VERBOSE ,
365 OPT_NO_EMPTY = 1<<OPTBIT_NO_EMPTY ,
366 OPT_UPTO_NUMBER = 1<<OPTBIT_UPTO_NUMBER,
367 OPT_UPTO_SIZE = 1<<OPTBIT_UPTO_SIZE ,
368 OPT_EOF_STRING = 1<<OPTBIT_EOF_STRING ,
369 OPT_INTERACTIVE = USE_FEATURE_XARGS_SUPPORT_CONFIRMATION((1<<OPTBIT_INTERACTIVE)) + 0,
370 OPT_TERMINATE = USE_FEATURE_XARGS_SUPPORT_TERMOPT( (1<<OPTBIT_TERMINATE )) + 0,
371 OPT_ZEROTERM = USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1<<OPTBIT_ZEROTERM )) + 0,
372};
373#define OPTION_STR "+trn:s:e::" \
374 USE_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
375 USE_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \
376 USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0")
Glenn L McGrath61796942003-10-10 12:10:18 +0000377
Denis Vlasenko06af2162007-02-03 17:28:39 +0000378int xargs_main(int argc, char **argv);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000379int xargs_main(int argc, char **argv)
Glenn L McGrath61796942003-10-10 12:10:18 +0000380{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000381 char **args;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000382 int i, n;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000383 xlist_t *list = NULL;
384 xlist_t *cur;
385 int child_error = 0;
386 char *max_args, *max_chars;
387 int n_max_arg;
388 size_t n_chars = 0;
389 long orig_arg_max;
390 const char *eof_str = "_";
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000391 unsigned opt;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000392 size_t n_max_chars;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000393#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
394 xlist_t* (*read_args)(xlist_t*, const char*, size_t, char*) = process_stdin;
395#else
396#define read_args process_stdin
Glenn L McGrath61796942003-10-10 12:10:18 +0000397#endif
398
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000399 opt = getopt32(argc, argv, OPTION_STR, &max_args, &max_chars, &eof_str);
Glenn L McGrath61796942003-10-10 12:10:18 +0000400
Denis Vlasenko6248a732006-09-29 08:20:30 +0000401 if (opt & OPT_ZEROTERM)
402 USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
Glenn L McGrath61796942003-10-10 12:10:18 +0000403
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000404 argv += optind;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000405 argc -= optind;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000406 if (!argc) {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000407 /* default behavior is to echo all the filenames */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000408 *argv = (char*)"echo";
Denis Vlasenko6248a732006-09-29 08:20:30 +0000409 argc++;
Glenn L McGrath61796942003-10-10 12:10:18 +0000410 }
411
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000412 orig_arg_max = ARG_MAX;
413 if (orig_arg_max == -1)
414 orig_arg_max = LONG_MAX;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000415 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048 */
416
417 if (opt & OPT_UPTO_SIZE) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000418 n_max_chars = xatoul_range(max_chars, 1, orig_arg_max);
Denis Vlasenko6248a732006-09-29 08:20:30 +0000419 for (i = 0; i < argc; i++) {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000420 n_chars += strlen(*argv) + 1;
Glenn L McGrath61796942003-10-10 12:10:18 +0000421 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000422 if (n_max_chars < n_chars) {
Denis Vlasenkoe1a0d482006-10-20 13:28:22 +0000423 bb_error_msg_and_die("cannot fit single argument within argument list size limit");
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000424 }
425 n_max_chars -= n_chars;
426 } else {
427 /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
428 have it at 1 meg). Things will work fine with a large ARG_MAX but it
429 will probably hurt the system more than it needs to; an array of this
430 size is allocated. */
431 if (orig_arg_max > 20 * 1024)
432 orig_arg_max = 20 * 1024;
433 n_max_chars = orig_arg_max;
Glenn L McGrath61796942003-10-10 12:10:18 +0000434 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000435 max_chars = xmalloc(n_max_chars);
436
Denis Vlasenko6248a732006-09-29 08:20:30 +0000437 if (opt & OPT_UPTO_NUMBER) {
Denis Vlasenko13858992006-10-08 12:49:22 +0000438 n_max_arg = xatoul_range(max_args, 1, INT_MAX);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000439 } else {
440 n_max_arg = n_max_chars;
Glenn L McGrath61796942003-10-10 12:10:18 +0000441 }
442
Denis Vlasenko6248a732006-09-29 08:20:30 +0000443 while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL ||
444 !(opt & OPT_NO_EMPTY))
Eric Andersen252183e2003-10-31 08:19:44 +0000445 {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000446 opt |= OPT_NO_EMPTY;
447 n = 0;
448 n_chars = 0;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000449#if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000450 for (cur = list; cur;) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000451 n_chars += cur->length;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000452 n++;
453 cur = cur->link;
454 if (n_chars > n_max_chars || (n == n_max_arg && cur)) {
455 if (opt & OPT_TERMINATE)
456 bb_error_msg_and_die("argument list too long");
457 break;
458 }
459 }
460#else
461 for (cur = list; cur; cur = cur->link) {
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000462 n_chars += cur->length;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000463 n++;
464 if (n_chars > n_max_chars || n == n_max_arg) {
465 break;
466 }
467 }
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000468#endif /* FEATURE_XARGS_SUPPORT_TERMOPT */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000469
Denis Vlasenko6248a732006-09-29 08:20:30 +0000470 /* allocate pointers for execvp:
471 argc*arg, n*arg from stdin, NULL */
472 args = xzalloc((n + argc + 1) * sizeof(char *));
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000473
Denis Vlasenko6248a732006-09-29 08:20:30 +0000474 /* store the command to be executed
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000475 (taken from the command line) */
Denis Vlasenko6248a732006-09-29 08:20:30 +0000476 for (i = 0; i < argc; i++)
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000477 args[i] = argv[i];
478 /* (taken from stdin) */
479 for (cur = list; n; cur = cur->link) {
480 args[i++] = cur->data;
481 n--;
482 }
483
Denis Vlasenko6248a732006-09-29 08:20:30 +0000484 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000485 for (i = 0; args[i]; i++) {
486 if (i)
487 fputc(' ', stderr);
488 fputs(args[i], stderr);
489 }
Denis Vlasenko6248a732006-09-29 08:20:30 +0000490 if (!(opt & OPT_INTERACTIVE))
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000491 fputc('\n', stderr);
492 }
Denis Vlasenko6248a732006-09-29 08:20:30 +0000493 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000494 child_error = xargs_exec(args);
495 }
496
497 /* clean up */
Denis Vlasenko6248a732006-09-29 08:20:30 +0000498 for (i = argc; args[i]; i++) {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000499 cur = list;
500 list = list->link;
501 free(cur);
502 }
503 free(args);
504 if (child_error > 0 && child_error != 123) {
505 break;
506 }
507 }
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000508 if (ENABLE_FEATURE_CLEAN_UP)
509 free(max_chars);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000510 return child_error;
Glenn L McGrath61796942003-10-10 12:10:18 +0000511}
512
513
514#ifdef TEST
515
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000516const char *applet_name = "debug stuff usage";
Glenn L McGrath61796942003-10-10 12:10:18 +0000517
518void bb_show_usage(void)
519{
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000520 fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000521 applet_name);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000522 exit(1);
Glenn L McGrath61796942003-10-10 12:10:18 +0000523}
524
525int main(int argc, char **argv)
526{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000527 return xargs_main(argc, argv);
Glenn L McGrath61796942003-10-10 12:10:18 +0000528}
Eric Andersen252183e2003-10-31 08:19:44 +0000529#endif /* TEST */