blob: 46a62cbf1d0b3f93305d4765122b178512fe16fc [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
Eric Andersen5b176932000-09-22 20:22:28 +00004 *
Glenn L McGrath61796942003-10-10 12:10:18 +00005 * (C) 2002,2003 by Vladimir Oleynik <dzo@simtreas.ru>
Glenn L McGrathf57674e2002-11-10 21:47:17 +00006 *
Glenn L McGrath61796942003-10-10 12:10:18 +00007 * Special thanks
Eric Andersenaff114c2004-04-14 17:51:38 +00008 * - Mark Whitley and Glenn McGrath for stimulus to rewrite :)
Glenn L McGrath61796942003-10-10 12:10:18 +00009 * - Mike Rendell <michael@cs.mun.ca>
10 * and David MacKenzie <djm@gnu.ai.mit.edu>.
Eric Andersen5b176932000-09-22 20:22:28 +000011 *
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000012 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersena37d5b72000-09-23 06:10:14 +000013 *
Glenn L McGrath40c94892003-10-30 22:51:33 +000014 * xargs is described in the Single Unix Specification v3 at
15 * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html
Eric Andersen5b176932000-09-22 20:22:28 +000016 */
Eric Andersen92a61c12000-09-22 20:01:23 +000017
Denys Vlasenko4f731ce2010-06-15 15:40:16 +020018//applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, _BB_DIR_USR_BIN, _BB_SUID_DROP, xargs))
19
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
Denys Vlasenko4f731ce2010-06-15 15:40:16 +0200354//usage:#define xargs_trivial_usage
355//usage: "[OPTIONS] [PROG ARGS]"
356//usage:#define xargs_full_usage "\n\n"
357//usage: "Run PROG on every item given by stdin\n"
358//usage: "\nOptions:"
359//usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(
360//usage: "\n -p Ask user whether to run each command"
361//usage: )
362//usage: "\n -r Don't run command if input is empty"
363//usage: IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(
364//usage: "\n -0 Input is separated by NUL characters"
365//usage: )
366//usage: "\n -t Print the command on stderr before execution"
367//usage: "\n -e[STR] STR stops input processing"
368//usage: "\n -n N Pass no more than N args to PROG"
369//usage: "\n -s N Pass command line of no more than N bytes"
370//usage: IF_FEATURE_XARGS_SUPPORT_TERMOPT(
371//usage: "\n -x Exit if size is exceeded"
372//usage: )
373//usage:#define xargs_example_usage
374//usage: "$ ls | xargs gzip\n"
375//usage: "$ find . -name '*.c' -print | xargs rm\n"
376
Denis Vlasenko6248a732006-09-29 08:20:30 +0000377/* Correct regardless of combination of CONFIG_xxx */
378enum {
379 OPTBIT_VERBOSE = 0,
380 OPTBIT_NO_EMPTY,
381 OPTBIT_UPTO_NUMBER,
382 OPTBIT_UPTO_SIZE,
383 OPTBIT_EOF_STRING,
Denis Vlasenko82ad0322008-08-04 21:30:55 +0000384 OPTBIT_EOF_STRING1,
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000385 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
386 IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,)
387 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,)
Glenn L McGrath61796942003-10-10 12:10:18 +0000388
Denis Vlasenko82ad0322008-08-04 21:30:55 +0000389 OPT_VERBOSE = 1 << OPTBIT_VERBOSE ,
390 OPT_NO_EMPTY = 1 << OPTBIT_NO_EMPTY ,
391 OPT_UPTO_NUMBER = 1 << OPTBIT_UPTO_NUMBER,
392 OPT_UPTO_SIZE = 1 << OPTBIT_UPTO_SIZE ,
393 OPT_EOF_STRING = 1 << OPTBIT_EOF_STRING , /* GNU: -e[<param>] */
394 OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E<param> */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000395 OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0,
396 OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0,
397 OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0,
Denis Vlasenko6248a732006-09-29 08:20:30 +0000398};
Denis Vlasenko82ad0322008-08-04 21:30:55 +0000399#define OPTION_STR "+trn:s:e::E:" \
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000400 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
401 IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \
402 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0")
Glenn L McGrath61796942003-10-10 12:10:18 +0000403
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000404int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000405int xargs_main(int argc, char **argv)
Glenn L McGrath61796942003-10-10 12:10:18 +0000406{
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200407 int i;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000408 int child_error = 0;
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200409 char *max_args;
410 char *max_chars;
411 char *buf;
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000412 unsigned opt;
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200413 int n_max_chars;
414 int n_max_arg;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000415#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200416 char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000417#else
418#define read_args process_stdin
Glenn L McGrath61796942003-10-10 12:10:18 +0000419#endif
420
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200421 INIT_G();
422
423 G.eof_str = NULL;
424 opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str);
Glenn L McGrath61796942003-10-10 12:10:18 +0000425
Denis Vlasenko82ad0322008-08-04 21:30:55 +0000426 /* -E ""? You may wonder why not just omit -E?
427 * This is used for portability:
428 * old xargs was using "_" as default for -E / -e */
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200429 if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0')
430 G.eof_str = NULL;
Denis Vlasenkocc08ad22008-08-03 19:12:25 +0000431
Denis Vlasenko6248a732006-09-29 08:20:30 +0000432 if (opt & OPT_ZEROTERM)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000433 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
Glenn L McGrath61796942003-10-10 12:10:18 +0000434
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000435 argv += optind;
Denis Vlasenko1b4b2cb2007-04-09 21:30:53 +0000436 argc -= optind;
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200437 if (!argv[0]) {
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000438 /* default behavior is to echo all the filenames */
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200439 *--argv = (char*)"echo";
Denis Vlasenko6248a732006-09-29 08:20:30 +0000440 argc++;
Glenn L McGrath61796942003-10-10 12:10:18 +0000441 }
442
Denys Vlasenkod7b52892010-04-09 14:58:40 +0200443 /* The Open Group Base Specifications Issue 6:
444 * "The xargs utility shall limit the command line length such that
445 * when the command line is invoked, the combined argument
446 * and environment lists (see the exec family of functions
447 * in the System Interfaces volume of IEEE Std 1003.1-2001)
448 * shall not exceed {ARG_MAX}-2048 bytes".
449 */
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200450 n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */
451 if (n_max_chars < 4*1024); /* paranoia */
452 n_max_chars = 4*1024;
Denys Vlasenkod7b52892010-04-09 14:58:40 +0200453 n_max_chars -= 2048;
454 /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200455 * have it at 1 meg). Things will work fine with a large ARG_MAX
456 * but it will probably hurt the system more than it needs to;
457 * an array of this size is allocated.
Denys Vlasenkod7b52892010-04-09 14:58:40 +0200458 */
459 if (n_max_chars > 20 * 1024)
460 n_max_chars = 20 * 1024;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000461
462 if (opt & OPT_UPTO_SIZE) {
Denys Vlasenkod7b52892010-04-09 14:58:40 +0200463 size_t n_chars = 0;
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200464 n_max_chars = xatou_range(max_chars, 1, INT_MAX);
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200465 for (i = 0; argv[i]; i++) {
466 n_chars += strlen(argv[i]) + 1;
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000467 }
468 n_max_chars -= n_chars;
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200469 if (n_max_chars <= 0) {
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200470 bb_error_msg_and_die("can't fit single argument within argument list size limit");
471 }
Glenn L McGrath61796942003-10-10 12:10:18 +0000472 }
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200473
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200474 buf = xzalloc(n_max_chars + 1);
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000475
Denys Vlasenkoc28cafb2010-06-14 12:38:36 +0200476 n_max_arg = n_max_chars;
Denis Vlasenko6248a732006-09-29 08:20:30 +0000477 if (opt & OPT_UPTO_NUMBER) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200478 n_max_arg = xatou_range(max_args, 1, INT_MAX);
Glenn L McGrath61796942003-10-10 12:10:18 +0000479 }
480
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200481 /* Allocate pointers for execvp */
482 /* We can statically allocate (argc + n_max_arg + 1) elements
483 * and do not bother with resizing args[], but on 64-bit machines
484 * this results in args[] vector which is ~8 times bigger
485 * than n_max_chars! That is, with n_max_chars == 20k,
486 * args[] will take 160k (!), which will most likely be
487 * almost entirely unused.
488 */
489 /* See store_param() for matching 256-step growth logic */
490 G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff));
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200491
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200492 /* Store the command to be executed, part 1 */
493 for (i = 0; argv[i]; i++)
494 G.args[i] = argv[i];
495
496 while (1) {
497 char *rem;
498
499 G.idx = argc;
500 rem = read_args(n_max_chars, n_max_arg, buf);
Denys Vlasenkoc28cafb2010-06-14 12:38:36 +0200501 store_param(NULL);
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200502
503 if (!G.args[argc]) {
504 if (*rem != '\0')
505 bb_error_msg_and_die("argument line too long");
506 if (opt & OPT_NO_EMPTY)
507 break;
508 }
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000509 opt |= OPT_NO_EMPTY;
Denys Vlasenkoaaa24e02010-06-13 12:43:54 +0200510
Denis Vlasenko6248a732006-09-29 08:20:30 +0000511 if (opt & (OPT_INTERACTIVE | OPT_VERBOSE)) {
Denys Vlasenkoc28cafb2010-06-14 12:38:36 +0200512 const char *fmt = " %s" + 1;
513 char **args = G.args;
514 for (i = 0; args[i]; i++) {
515 fprintf(stderr, fmt, args[i]);
516 fmt = " %s";
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000517 }
Denis Vlasenko6248a732006-09-29 08:20:30 +0000518 if (!(opt & OPT_INTERACTIVE))
Denys Vlasenko19ced5c2010-06-06 21:53:09 +0200519 bb_putchar_stderr('\n');
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000520 }
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200521
Denis Vlasenko6248a732006-09-29 08:20:30 +0000522 if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) {
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200523 child_error = xargs_exec();
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000524 }
525
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000526 if (child_error > 0 && child_error != 123) {
527 break;
528 }
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200529
530 overlapping_strcpy(buf, rem);
Denis Vlasenkod50dda82008-06-15 05:40:56 +0000531 } /* while */
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200532
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200533 if (ENABLE_FEATURE_CLEAN_UP) {
534 free(G.args);
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200535 free(buf);
Denys Vlasenko7a4021d2010-06-14 00:57:05 +0200536 }
Denys Vlasenkod5fa1a02010-06-13 03:43:43 +0200537
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000538 return child_error;
Glenn L McGrath61796942003-10-10 12:10:18 +0000539}
540
541
542#ifdef TEST
543
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000544const char *applet_name = "debug stuff usage";
Glenn L McGrath61796942003-10-10 12:10:18 +0000545
546void bb_show_usage(void)
547{
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000548 fprintf(stderr, "Usage: %s [-p] [-r] [-t] -[x] [-n max_arg] [-s max_chars]\n",
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000549 applet_name);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +0000550 exit(EXIT_FAILURE);
Glenn L McGrath61796942003-10-10 12:10:18 +0000551}
552
553int main(int argc, char **argv)
554{
Glenn L McGrath09c295a2003-10-30 22:47:16 +0000555 return xargs_main(argc, argv);
Glenn L McGrath61796942003-10-10 12:10:18 +0000556}
Eric Andersen252183e2003-10-31 08:19:44 +0000557#endif /* TEST */