blob: 8caaff91cec7b9cfe51503f007d81b3873072c45 [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
Denys Vlasenko7fb68f12010-05-09 04:22:48 +020020//kbuild:lib-$(CONFIG_XARGS) += xargs.o
Denys Vlasenko237aece2010-06-15 10:18:01 +020021
Denys Vlasenko7fb68f12010-05-09 04:22:48 +020022//config:config XARGS
23//config: bool "xargs"
Denys Vlasenko2f32bf82010-06-06 04:14:28 +020024//config: default y
Denys Vlasenko7fb68f12010-05-09 04:22:48 +020025//config: help
26//config: xargs is used to execute a specified command for
27//config: every item from standard input.
28//config:
29//config:config FEATURE_XARGS_SUPPORT_CONFIRMATION
30//config: bool "Enable -p: prompt and confirmation"
Denys Vlasenko2f32bf82010-06-06 04:14:28 +020031//config: default y
Denys Vlasenko7fb68f12010-05-09 04:22:48 +020032//config: depends on XARGS
33//config: help
34//config: Support -p: prompt the user whether to run each command
35//config: line and read a line from the terminal.
36//config:
37//config:config FEATURE_XARGS_SUPPORT_QUOTES
38//config: bool "Enable single and double quotes and backslash"
Denys Vlasenko2f32bf82010-06-06 04:14:28 +020039//config: default y
Denys Vlasenko7fb68f12010-05-09 04:22:48 +020040//config: depends on XARGS
41//config: help
42//config: Support quoting in the input.
43//config:
44//config:config FEATURE_XARGS_SUPPORT_TERMOPT
45//config: bool "Enable -x: exit if -s or -n is exceeded"
Denys Vlasenko2f32bf82010-06-06 04:14:28 +020046//config: default y
Denys Vlasenko7fb68f12010-05-09 04:22:48 +020047//config: depends on XARGS
48//config: help
49//config: Support -x: exit if the command size (see the -s or -n option)
50//config: is exceeded.
51//config:
52//config:config FEATURE_XARGS_SUPPORT_ZERO_TERM
53//config: bool "Enable -0: NUL-terminated input"
Denys Vlasenko2f32bf82010-06-06 04:14:28 +020054//config: default y
Denys Vlasenko7fb68f12010-05-09 04:22:48 +020055//config: depends on XARGS
56//config: help
57//config: Support -0: input items are terminated by a NUL character
58//config: instead of whitespace, and the quotes and backslash
59//config: are not special.
60
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000061#include "libbb.h"
Glenn L McGrath61796942003-10-10 12:10:18 +000062/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
63 We try to make it as large as possible. */
64#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
Denys Vlasenkod7b52892010-04-09 14:58:40 +020065# define ARG_MAX sysconf(_SC_ARG_MAX)
Glenn L McGrath61796942003-10-10 12:10:18 +000066#endif
Denys Vlasenkod7b52892010-04-09 14:58:40 +020067#if !defined(ARG_MAX)
68# define ARG_MAX 470
Glenn L McGrath61796942003-10-10 12:10:18 +000069#endif
70
Denys Vlasenko7a4021d2010-06-14 00:57:05 +020071/* 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
Glenn L McGrath61796942003-10-10 12:10:18 +000077
78#ifdef TEST
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000079# ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
80# define ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 1
Glenn L McGrath61796942003-10-10 12:10:18 +000081# endif
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000082# ifndef ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
83# define ENABLE_FEATURE_XARGS_SUPPORT_QUOTES 1
Glenn L McGrath61796942003-10-10 12:10:18 +000084# endif
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000085# ifndef ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT
86# define ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT 1
Glenn L McGrath61796942003-10-10 12:10:18 +000087# endif
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +000088# ifndef ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
89# define ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 1
Glenn L McGrath61796942003-10-10 12:10:18 +000090# endif
91#endif
92
Denys Vlasenko7a4021d2010-06-14 00:57:05 +020093
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
Glenn L McGrathf57674e2002-11-10 21:47:17 +0000103/*
Denys Vlasenkoaaa24e02010-06-13 12:43:54 +0200104 * This function has special algorithm.
105 * Don't use fork and include to main!
106 */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200107static int xargs_exec(void)
Glenn L McGrathf57674e2002-11-10 21:47:17 +0000108{
Denis Vlasenko6248a732006-09-29 08:20:30 +0000109 int status;
Glenn L McGrath61796942003-10-10 12:10:18 +0000110
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200111 status = spawn_and_wait(G.args);
Denis Vlasenkocd7001f2007-04-09 21:32:30 +0000112 if (status < 0) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200113 bb_simple_perror_msg(G.args[0]);
Denis Vlasenkocd7001f2007-04-09 21:32:30 +0000114 return errno == ENOENT ? 127 : 126;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000115 }
Denis Vlasenkocd7001f2007-04-09 21:32:30 +0000116 if (status == 255) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200117 bb_error_msg("%s: exited with status 255; aborting", G.args[0]);
Denis Vlasenko6248a732006-09-29 08:20:30 +0000118 return 124;
119 }
Denys Vlasenko8531d762010-03-18 22:44:00 +0100120 if (status >= 0x180) {
Denis Vlasenko6248a732006-09-29 08:20:30 +0000121 bb_error_msg("%s: terminated by signal %d",
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200122 G.args[0], status - 0x180);
Denis Vlasenko6248a732006-09-29 08:20:30 +0000123 return 125;
124 }
Denis Vlasenkocd7001f2007-04-09 21:32:30 +0000125 if (status)
Denis Vlasenko6248a732006-09-29 08:20:30 +0000126 return 123;
127 return 0;
Glenn L McGrath61796942003-10-10 12:10:18 +0000128}
Glenn L McGrath99825962003-10-09 11:06:45 +0000129
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200130/* In POSIX/C locale isspace is only these chars: "\t\n\v\f\r" and space.
131 * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13.
132 */
133#define ISSPACE(a) ({ unsigned char xargs__isspace = (a) - 9; xargs__isspace == (' ' - 9) || xargs__isspace <= (13 - 9); })
Glenn L McGrath61796942003-10-10 12:10:18 +0000134
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200135static 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.
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200153 * On entry, buf[] may contain some "seed chars" which are to become
154 * the beginning of the first parameter.
155 */
156
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000157#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200158static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
Glenn L McGrath61796942003-10-10 12:10:18 +0000159{
160#define NORM 0
161#define QUOTE 1
162#define BACKSLASH 2
163#define SPACE 4
Denys Vlasenko237aece2010-06-15 10:18:01 +0200164 char q = '\0'; /* quote char */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000165 char state = NORM;
Denys Vlasenko237aece2010-06-15 10:18:01 +0200166 char *s = buf; /* start of the word */
167 char *p = s + strlen(buf); /* end of the word */
Glenn L McGrath61796942003-10-10 12:10:18 +0000168
Denys Vlasenko237aece2010-06-15 10:18:01 +0200169 buf += n_max_chars; /* past buffer's end */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200170
171 /* "goto ret" is used instead of "break" to make control flow
172 * more obvious: */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000173
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200174 while (1) {
175 int c = getchar();
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000176 if (c == EOF) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200177 if (p != s)
178 goto close_word;
179 goto ret;
Glenn L McGrath61796942003-10-10 12:10:18 +0000180 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000181 if (state == BACKSLASH) {
182 state = NORM;
183 goto set;
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200184 }
185 if (state == QUOTE) {
Denis Vlasenko58394b12007-04-15 08:38:50 +0000186 if (c != q)
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000187 goto set;
Denis Vlasenko58394b12007-04-15 08:38:50 +0000188 q = '\0';
189 state = NORM;
Denis Vlasenko51742f42007-04-12 00:32:05 +0000190 } else { /* if (state == NORM) */
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000191 if (ISSPACE(c)) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200192 if (p != s) {
193 close_word:
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000194 state = SPACE;
Denis Vlasenko58394b12007-04-15 08:38:50 +0000195 c = '\0';
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000196 goto set;
197 }
198 } else {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000199 if (c == '\\') {
200 state = BACKSLASH;
201 } else if (c == '\'' || c == '"') {
202 q = c;
203 state = QUOTE;
204 } else {
Denis Vlasenko58394b12007-04-15 08:38:50 +0000205 set:
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000206 *p++ = c;
207 }
208 }
209 }
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000210 if (state == SPACE) { /* word's delimiter or EOF detected */
Eric Andersen252183e2003-10-31 08:19:44 +0000211 if (q) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000212 bb_error_msg_and_die("unmatched %s quote",
Eric Andersen252183e2003-10-31 08:19:44 +0000213 q == '\'' ? "single" : "double");
214 }
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200215 /* A full word is loaded */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200216 if (G.eof_str) {
217 if (strcmp(s, G.eof_str) == 0) {
218 while (getchar() != EOF)
219 continue;
220 p = s;
221 goto ret;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000222 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000223 }
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200224 store_param(s);
225 dbg_msg("args[]:'%s'", s);
226 s = p;
227 n_max_arg--;
Denys Vlasenko237aece2010-06-15 10:18:01 +0200228 if (n_max_arg == 0) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200229 goto ret;
230 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000231 state = NORM;
Denys Vlasenko237aece2010-06-15 10:18:01 +0200232 }
233 if (p == buf) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200234 goto ret;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000235 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000236 }
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200237 ret:
238 *p = '\0';
Denys Vlasenkoc28cafb2010-06-14 12:38:36 +0200239 /* store_param(NULL) - caller will do it */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200240 dbg_msg("return:'%s'", s);
241 return s;
Glenn L McGrathf57674e2002-11-10 21:47:17 +0000242}
Glenn L McGrath61796942003-10-10 12:10:18 +0000243#else
Eric Andersen252183e2003-10-31 08:19:44 +0000244/* The variant does not support single quotes, double quotes or backslash */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200245static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf)
Eric Andersen92a61c12000-09-22 20:01:23 +0000246{
Denys Vlasenko237aece2010-06-15 10:18:01 +0200247 char *s = buf; /* start of the word */
248 char *p = s + strlen(buf); /* end of the word */
Glenn L McGrathadd3ead2003-10-04 14:44:27 +0000249
Denys Vlasenko237aece2010-06-15 10:18:01 +0200250 buf += n_max_chars; /* past buffer's end */
Eric Andersen92a61c12000-09-22 20:01:23 +0000251
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200252 while (1) {
253 int c = getchar();
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000254 if (c == EOF) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200255 if (p == s)
256 goto ret;
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200257 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000258 if (c == EOF || ISSPACE(c)) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200259 if (p == s)
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000260 continue;
261 c = EOF;
Glenn L McGrath61796942003-10-10 12:10:18 +0000262 }
Denis Vlasenko58394b12007-04-15 08:38:50 +0000263 *p++ = (c == EOF ? '\0' : c);
"Vladimir N. Oleynik"59c4e5c2006-01-30 13:51:50 +0000264 if (c == EOF) { /* word's delimiter or EOF detected */
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200265 /* A full word is loaded */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200266 if (G.eof_str) {
267 if (strcmp(s, G.eof_str) == 0) {
268 while (getchar() != EOF)
269 continue;
270 p = s;
271 goto ret;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000272 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000273 }
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200274 store_param(s);
275 dbg_msg("args[]:'%s'", s);
276 s = p;
277 n_max_arg--;
Denys Vlasenko237aece2010-06-15 10:18:01 +0200278 if (n_max_arg == 0) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200279 goto ret;
280 }
Denys Vlasenko237aece2010-06-15 10:18:01 +0200281 }
282 if (p == buf) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200283 goto ret;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000284 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000285 }
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200286 ret:
287 *p = '\0';
Denys Vlasenkoc28cafb2010-06-14 12:38:36 +0200288 /* store_param(NULL) - caller will do it */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200289 dbg_msg("return:'%s'", s);
290 return s;
Eric Andersen92a61c12000-09-22 20:01:23 +0000291}
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000292#endif /* FEATURE_XARGS_SUPPORT_QUOTES */
Glenn L McGrath61796942003-10-10 12:10:18 +0000293
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000294#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200295static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf)
Glenn L McGrath61796942003-10-10 12:10:18 +0000296{
Denys Vlasenko237aece2010-06-15 10:18:01 +0200297 char *s = buf; /* start of the word */
298 char *p = s + strlen(buf); /* end of the word */
Glenn L McGrath61796942003-10-10 12:10:18 +0000299
Denys Vlasenko237aece2010-06-15 10:18:01 +0200300 buf += n_max_chars; /* past buffer's end */
Glenn L McGrath61796942003-10-10 12:10:18 +0000301
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200302 while (1) {
303 int c = getchar();
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000304 if (c == EOF) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200305 if (p == s)
306 goto ret;
Denis Vlasenko58394b12007-04-15 08:38:50 +0000307 c = '\0';
Glenn L McGrath61796942003-10-10 12:10:18 +0000308 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000309 *p++ = c;
Denis Vlasenko58394b12007-04-15 08:38:50 +0000310 if (c == '\0') { /* word's delimiter or EOF detected */
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200311 /* A full word is loaded */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200312 store_param(s);
313 dbg_msg("args[]:'%s'", s);
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200314 s = p;
Denys Vlasenkof7e929e2010-06-15 10:02:04 +0200315 n_max_arg--;
Denys Vlasenko237aece2010-06-15 10:18:01 +0200316 if (n_max_arg == 0) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200317 goto ret;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000318 }
Denys Vlasenko237aece2010-06-15 10:18:01 +0200319 }
320 if (p == buf) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200321 goto ret;
Glenn L McGrath61796942003-10-10 12:10:18 +0000322 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000323 }
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200324 ret:
325 *p = '\0';
Denys Vlasenkoc28cafb2010-06-14 12:38:36 +0200326 /* store_param(NULL) - caller will do it */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200327 dbg_msg("return:'%s'", s);
328 return s;
Glenn L McGrath61796942003-10-10 12:10:18 +0000329}
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000330#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
Glenn L McGrath61796942003-10-10 12:10:18 +0000331
Denys Vlasenkoaaa24e02010-06-13 12:43:54 +0200332#if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
333/* Prompt the user for a response, and
334 if the user responds affirmatively, return true;
335 otherwise, return false. Uses "/dev/tty", not stdin. */
336static int xargs_ask_confirmation(void)
337{
338 FILE *tty_stream;
339 int c, savec;
340
341 tty_stream = xfopen_for_read(CURRENT_TTY);
342 fputs(" ?...", stderr);
343 fflush_all();
344 c = savec = getc(tty_stream);
345 while (c != EOF && c != '\n')
346 c = getc(tty_stream);
347 fclose(tty_stream);
348 return (savec == 'y' || savec == 'Y');
349}
350#else
351# define xargs_ask_confirmation() 1
352#endif
353
Denis Vlasenko6248a732006-09-29 08:20:30 +0000354/* Correct regardless of combination of CONFIG_xxx */
355enum {
356 OPTBIT_VERBOSE = 0,
357 OPTBIT_NO_EMPTY,
358 OPTBIT_UPTO_NUMBER,
359 OPTBIT_UPTO_SIZE,
360 OPTBIT_EOF_STRING,
Denis Vlasenko82ad0322008-08-04 21:30:55 +0000361 OPTBIT_EOF_STRING1,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000362 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
363 IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,)
364 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,)
Glenn L McGrath61796942003-10-10 12:10:18 +0000365
Denis Vlasenko82ad0322008-08-04 21:30:55 +0000366 OPT_VERBOSE = 1 << OPTBIT_VERBOSE ,
367 OPT_NO_EMPTY = 1 << OPTBIT_NO_EMPTY ,
368 OPT_UPTO_NUMBER = 1 << OPTBIT_UPTO_NUMBER,
369 OPT_UPTO_SIZE = 1 << OPTBIT_UPTO_SIZE ,
370 OPT_EOF_STRING = 1 << OPTBIT_EOF_STRING , /* GNU: -e[<param>] */
371 OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E<param> */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000372 OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0,
373 OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0,
374 OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0,
Denis Vlasenko6248a732006-09-29 08:20:30 +0000375};
Denis Vlasenko82ad0322008-08-04 21:30:55 +0000376#define OPTION_STR "+trn:s:e::E:" \
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000377 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
378 IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \
379 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0")
Glenn L McGrath61796942003-10-10 12:10:18 +0000380
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000381int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000382int xargs_main(int argc, char **argv)
Glenn L McGrath61796942003-10-10 12:10:18 +0000383{
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200384 int i;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000385 int child_error = 0;
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200386 char *max_args;
387 char *max_chars;
388 char *buf;
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000389 unsigned opt;
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200390 int n_max_chars;
391 int n_max_arg;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000392#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200393 char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000394#else
395#define read_args process_stdin
Glenn L McGrath61796942003-10-10 12:10:18 +0000396#endif
397
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200398 INIT_G();
399
400 G.eof_str = NULL;
401 opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str);
Glenn L McGrath61796942003-10-10 12:10:18 +0000402
Denis Vlasenko82ad0322008-08-04 21:30:55 +0000403 /* -E ""? You may wonder why not just omit -E?
404 * This is used for portability:
405 * old xargs was using "_" as default for -E / -e */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200406 if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0')
407 G.eof_str = NULL;
Denis Vlasenkocc08ad22008-08-03 19:12:25 +0000408
Denis Vlasenko6248a732006-09-29 08:20:30 +0000409 if (opt & OPT_ZEROTERM)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000410 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
Glenn L McGrath61796942003-10-10 12:10:18 +0000411
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000412 argv += optind;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000413 argc -= optind;
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200414 if (!argv[0]) {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000415 /* default behavior is to echo all the filenames */
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200416 *--argv = (char*)"echo";
Denis Vlasenko6248a732006-09-29 08:20:30 +0000417 argc++;
Glenn L McGrath61796942003-10-10 12:10:18 +0000418 }
419
Denys Vlasenkod7b52892010-04-09 14:58:40 +0200420 /* The Open Group Base Specifications Issue 6:
421 * "The xargs utility shall limit the command line length such that
422 * when the command line is invoked, the combined argument
423 * and environment lists (see the exec family of functions
424 * in the System Interfaces volume of IEEE Std 1003.1-2001)
425 * shall not exceed {ARG_MAX}-2048 bytes".
426 */
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200427 n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */
428 if (n_max_chars < 4*1024); /* paranoia */
429 n_max_chars = 4*1024;
Denys Vlasenkod7b52892010-04-09 14:58:40 +0200430 n_max_chars -= 2048;
431 /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200432 * have it at 1 meg). Things will work fine with a large ARG_MAX
433 * but it will probably hurt the system more than it needs to;
434 * an array of this size is allocated.
Denys Vlasenkod7b52892010-04-09 14:58:40 +0200435 */
436 if (n_max_chars > 20 * 1024)
437 n_max_chars = 20 * 1024;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000438
439 if (opt & OPT_UPTO_SIZE) {
Denys Vlasenkod7b52892010-04-09 14:58:40 +0200440 size_t n_chars = 0;
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200441 n_max_chars = xatou_range(max_chars, 1, INT_MAX);
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200442 for (i = 0; argv[i]; i++) {
443 n_chars += strlen(argv[i]) + 1;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000444 }
445 n_max_chars -= n_chars;
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200446 if (n_max_chars <= 0) {
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200447 bb_error_msg_and_die("can't fit single argument within argument list size limit");
448 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000449 }
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200450
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200451 buf = xzalloc(n_max_chars + 1);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000452
Denys Vlasenkoc28cafb2010-06-14 12:38:36 +0200453 n_max_arg = n_max_chars;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000454 if (opt & OPT_UPTO_NUMBER) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200455 n_max_arg = xatou_range(max_args, 1, INT_MAX);
Glenn L McGrath61796942003-10-10 12:10:18 +0000456 }
457
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200458 /* Allocate pointers for execvp */
459 /* We can statically allocate (argc + n_max_arg + 1) elements
460 * and do not bother with resizing args[], but on 64-bit machines
461 * this results in args[] vector which is ~8 times bigger
462 * than n_max_chars! That is, with n_max_chars == 20k,
463 * args[] will take 160k (!), which will most likely be
464 * almost entirely unused.
465 */
466 /* See store_param() for matching 256-step growth logic */
467 G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff));
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200468
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200469 /* Store the command to be executed, part 1 */
470 for (i = 0; argv[i]; i++)
471 G.args[i] = argv[i];
472
473 while (1) {
474 char *rem;
475
476 G.idx = argc;
477 rem = read_args(n_max_chars, n_max_arg, buf);
Denys Vlasenkoc28cafb2010-06-14 12:38:36 +0200478 store_param(NULL);
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200479
480 if (!G.args[argc]) {
481 if (*rem != '\0')
482 bb_error_msg_and_die("argument line too long");
483 if (opt & OPT_NO_EMPTY)
484 break;
485 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000486 opt |= OPT_NO_EMPTY;
Denys Vlasenkoaaa24e02010-06-13 12:43:54 +0200487
Denis Vlasenko6248a732006-09-29 08:20:30 +0000488 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
Denys Vlasenkoc28cafb2010-06-14 12:38:36 +0200489 const char *fmt = " %s" + 1;
490 char **args = G.args;
491 for (i = 0; args[i]; i++) {
492 fprintf(stderr, fmt, args[i]);
493 fmt = " %s";
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000494 }
Denis Vlasenko6248a732006-09-29 08:20:30 +0000495 if (!(opt & OPT_INTERACTIVE))
Denys Vlasenko19ced5c2010-06-06 21:53:09 +0200496 bb_putchar_stderr('\n');
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000497 }
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200498
Denis Vlasenko6248a732006-09-29 08:20:30 +0000499 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200500 child_error = xargs_exec();
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000501 }
502
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000503 if (child_error > 0 && child_error != 123) {
504 break;
505 }
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200506
507 overlapping_strcpy(buf, rem);
Denis Vlasenkod50dda82008-06-15 05:40:56 +0000508 } /* while */
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200509
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200510 if (ENABLE_FEATURE_CLEAN_UP) {
511 free(G.args);
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200512 free(buf);
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200513 }
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200514
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000515 return child_error;
Glenn L McGrath61796942003-10-10 12:10:18 +0000516}
517
518
519#ifdef TEST
520
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000521const char *applet_name = "debug stuff usage";
Glenn L McGrath61796942003-10-10 12:10:18 +0000522
523void bb_show_usage(void)
524{
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000525 fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000526 applet_name);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +0000527 exit(EXIT_FAILURE);
Glenn L McGrath61796942003-10-10 12:10:18 +0000528}
529
530int main(int argc, char **argv)
531{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000532 return xargs_main(argc, argv);
Glenn L McGrath61796942003-10-10 12:10:18 +0000533}
Eric Andersen252183e2003-10-31 08:19:44 +0000534#endif /* TEST */