summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2000-09-22 20:22:28 +0000
committerEric Andersen <andersen@codepoet.org>2000-09-22 20:22:28 +0000
commit5b17693f0a07d0fa8af08e3c0d6b43c7b826a13d (patch)
treeba51e2cba249df7bf64b5826ebbbe654a4d24250
parentebc0dd7a8a553ee1a3b4293975b02aa1578cac07 (diff)
downloadbusybox-w32-5b17693f0a07d0fa8af08e3c0d6b43c7b826a13d.tar.gz
busybox-w32-5b17693f0a07d0fa8af08e3c0d6b43c7b826a13d.tar.bz2
busybox-w32-5b17693f0a07d0fa8af08e3c0d6b43c7b826a13d.zip
Use minix xargs instead, and update docs accordingly
-Erik
-rw-r--r--applets/usage.c23
-rw-r--r--docs/busybox.pod28
-rw-r--r--docs/busybox.sgml37
-rw-r--r--findutils/xargs.c1019
-rw-r--r--usage.c23
-rw-r--r--xargs.c1019
6 files changed, 303 insertions, 1846 deletions
diff --git a/applets/usage.c b/applets/usage.c
index 8e0247941..236bc9460 100644
--- a/applets/usage.c
+++ b/applets/usage.c
@@ -592,6 +592,9 @@ const char ls_usage[] =
592#ifdef BB_FEATURE_LS_FILETYPES 592#ifdef BB_FEATURE_LS_FILETYPES
593 "p" 593 "p"
594#endif 594#endif
595#ifdef BB_FEATURE_LS_FOLLOWLINKS
596 "L"
597#endif
595#ifdef BB_FEATURE_LS_RECURSIVE 598#ifdef BB_FEATURE_LS_RECURSIVE
596 "R" 599 "R"
597#endif 600#endif
@@ -640,6 +643,9 @@ const char ls_usage[] =
640#ifdef BB_FEATURE_LS_FILETYPES 643#ifdef BB_FEATURE_LS_FILETYPES
641 "\t-p\tappend indicator (one of /=@|) to entries\n" 644 "\t-p\tappend indicator (one of /=@|) to entries\n"
642#endif 645#endif
646#ifdef BB_FEATURE_LS_FOLLOWLINKS
647 "\t-L\tlist entries pointed to by symbolic links\n"
648#endif
643#ifdef BB_FEATURE_LS_RECURSIVE 649#ifdef BB_FEATURE_LS_RECURSIVE
644 "\t-R\tlist subdirectories recursively\n" 650 "\t-R\tlist subdirectories recursively\n"
645#endif 651#endif
@@ -1433,14 +1439,15 @@ const char whoami_usage[] =
1433#endif 1439#endif
1434 1440
1435#if defined BB_XARGS 1441#if defined BB_XARGS
1436const char xargs_usage[] = 1442const char xargs_usage[] = "xargs [OPTIONS] [COMMAND] [ARGS...]\n"
1437 "xargs [-0prtx] [-e[eof-str]] [-i[replace-str]] [-l[max-lines]]\n" 1443#ifndef BB_FEATURE_TRIVIAL_HELP
1438 "[-n max-args] [-s max-chars] [-P max-procs] [--null] [--eof[=eof-str]]\n" 1444 "\nExecutes COMMAND on every item given by standard input.\n\n"
1439 "[--replace[=replace-str]] [--max-lines[=max-lines]] [--interactive]\n" 1445 "Options:\n"
1440 "[--max-chars=max-chars] [--verbose] [--exit] [--max-procs=max-procs]\n" 1446 "\t-t\tPrint the command just before it is run\n"
1441 "[--max-args=max-args] [--no-run-if-empty] [--help]\n" 1447 "\t-l LEN\tUse LEN as maximum line length (default 490, max 1023)\n"
1442 "[command [initial-arguments]]\n" 1448 "\t-e ENDING\tAppend ENDING to the command before executing it.\n"
1443 "\nBuild and execute command on lines from standard input.\n"; 1449#endif
1450 ;
1444#endif 1451#endif
1445 1452
1446#if defined BB_YES 1453#if defined BB_YES
diff --git a/docs/busybox.pod b/docs/busybox.pod
index e12c8243c..5caf1de7d 100644
--- a/docs/busybox.pod
+++ b/docs/busybox.pod
@@ -64,8 +64,8 @@ mkfifo, mkfs.minix, mknod, mkswap, mktemp, more, mount, mt, mv, nc, nslookup,
64ping, poweroff, printf, ps, pwd, rdate, reboot, renice, reset, rm, rmdir, 64ping, poweroff, printf, ps, pwd, rdate, reboot, renice, reset, rm, rmdir,
65rmmod, sed, setkeycodes, sh, sleep, sort, swapoff, swapon, sync, syslogd, tail, 65rmmod, sed, setkeycodes, sh, sleep, sort, swapoff, swapon, sync, syslogd, tail,
66tar, tee, telnet, test, touch, tr, true, tty, umount, uname, uniq, unix2dos, 66tar, tee, telnet, test, touch, tr, true, tty, umount, uname, uniq, unix2dos,
67unrpm, update, uptime, usleep, uudecode, uuencode, wc, which, whoami, yes, 67unrpm, update, uptime, usleep, uudecode, uuencode, wc, which, whoami, xargs,
68zcat, [ 68yes, zcat, [
69 69
70------------------------------- 70-------------------------------
71 71
@@ -1105,7 +1105,7 @@ Example:
1105 1105
1106=item ls 1106=item ls
1107 1107
1108Usage: ls [B<-1acdelnpuxACFR>] [filenames...] 1108Usage: ls [B<-1acdelnpuxACFLR>] [filenames...]
1109 1109
1110Options: 1110Options:
1111 1111
@@ -1124,6 +1124,7 @@ Options:
1124 -C list entries by columns 1124 -C list entries by columns
1125 -F append indicator (one of */=@|) to entries 1125 -F append indicator (one of */=@|) to entries
1126 -R list subdirectories recursively 1126 -R list subdirectories recursively
1127 -L list entries pointed to by symbolic links
1127 1128
1128------------------------------- 1129-------------------------------
1129 1130
@@ -2080,6 +2081,25 @@ Example:
2080 2081
2081------------------------------- 2082-------------------------------
2082 2083
2084=item xargs
2085
2086Usage: xargs [OPTIONS] [COMMAND] [ARGS...]
2087
2088Executes COMMAND on every item given by standard input.
2089
2090Options:
2091
2092 -t Print the command just before it is run
2093 -l LEN Use LEN as maximum line length (default 490, max 1023)
2094 -e ENDING Append ENDING to the command before executing it.
2095
2096Example:
2097
2098 $ ls | xargs gzip
2099 $ find . -name '*.c' -print | xargs rm
2100
2101-------------------------------
2102
2083=item yes 2103=item yes
2084 2104
2085Usage: yes [OPTION]... [STRING]... 2105Usage: yes [OPTION]... [STRING]...
@@ -2182,4 +2202,4 @@ Enrique Zanardi <ezanardi@ull.es>
2182 2202
2183=cut 2203=cut
2184 2204
2185# $Id: busybox.pod,v 1.70 2000/09/21 02:06:35 andersen Exp $ 2205# $Id: busybox.pod,v 1.71 2000/09/22 20:22:27 andersen Exp $
diff --git a/docs/busybox.sgml b/docs/busybox.sgml
index e8a91fa05..e213ca1b2 100644
--- a/docs/busybox.sgml
+++ b/docs/busybox.sgml
@@ -1922,6 +1922,7 @@
1922 -A Do not list implied . and .. 1922 -A Do not list implied . and ..
1923 -C List entries by columns 1923 -C List entries by columns
1924 -F Append indicator (one of */=@|) to entries 1924 -F Append indicator (one of */=@|) to entries
1925 -L list entries pointed to by symbolic links
1925 -R List subdirectories recursively 1926 -R List subdirectories recursively
1926 </screen> 1927 </screen>
1927 </para> 1928 </para>
@@ -3659,6 +3660,42 @@
3659 </para> 3660 </para>
3660 </sect1> 3661 </sect1>
3661 3662
3663 <sect1 id="xargs">
3664 <title>xargs</title>
3665
3666 <para>
3667 Usage: xargs [OPTIONS] [COMMAND] [ARGS...]
3668 </para>
3669
3670 <para>
3671 Executes COMMAND on every item given by standard input.
3672 </para>
3673
3674 <para>
3675 Options:
3676 </para>
3677
3678 <para>
3679 <screen>
3680 -t Print the command just before it is run
3681 -l LEN Use LEN as maximum line length (default 490, max 1023)
3682 -e ENDING Append ENDING to the command before executing it.
3683 </screen>
3684 </para>
3685
3686
3687 <para>
3688 Example:
3689 </para>
3690
3691 <para>
3692 <screen>
3693 $ ls | xargs gzip
3694 $ find . -name '*.c' -print | xargs rm
3695 </screen>
3696 </para>
3697 </sect1>
3698
3662 <sect1 id="yes"> 3699 <sect1 id="yes">
3663 <title>yes</title> 3700 <title>yes</title>
3664 3701
diff --git a/findutils/xargs.c b/findutils/xargs.c
index adf1f134c..be1fada78 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -1,923 +1,116 @@
1/* xargs for busybox -- using GNU xargs till we can get something 1/* minix xargs - Make and execute commands
2 * better. minix xargs is a bit smaller... */ 2 * Author: Ian Nicholls: 1 Mar 90 */
3
4/*
5 * xargs - Accept words from stdin until, combined with the arguments
6 * given on the command line, just fit into the command line limit.
7 * Then, execute the result.
8 * e.g. ls | xargs compress
9 * find . -name '*.s' -print | xargs ar qv libc.a
10 *
11 * flags: -t Print the command just before it is run
12 * -l len Use len as maximum line length (default 490, max 1023)
13 * -e ending Append ending to the command before executing it.
14 *
15 * Exits with: 0 No errors.
16 * 1 If any system(3) call returns a nonzero status.
17 * 2 Usage error
18 * 3 Line length too short to contain some single argument.
19 *
20 * Examples: xargs ar qv libc.a < liborder # Create a new libc.a
21 * find . -name '*.s' -print | xargs rm # Remove all .s files
22 * find . -type f ! -name '*.Z' \ # Compress old files.
23 * -atime +60 -print | xargs compress -v
24 *
25 * Bugs: If the command contains unquoted wildflags, then the system(3) call
26 * call may expand this to larger than the maximum line size.
27 * The command is not executed if nothing was read from stdin.
28 * xargs may give up too easily when the command returns nonzero.
29 */
30#define USAGE "usage: xargs [-t] [-l len] [-e endargs] command [args...]\n"
3 31
4/* xargs -- build and execute command lines from standard input
5 Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21/* Written by Mike Rendell <michael@cs.mun.ca>
22 and David MacKenzie <djm@gnu.ai.mit.edu>. */
23
24#include "internal.h"
25
26#define HAVE_STRING_H 1
27#define HAVE_SYS_WAIT_H 1
28#define HAVE_UNISTD_H 1
29#define HAVE_LIMITS_H 1
30#define STDC_HEADERS 1
31
32#include <sys/types.h> /* For pid_t. */
33#if HAVE_SYS_WAIT_H
34#include <sys/wait.h>
35#endif
36
37#ifndef WIFSTOPPED
38#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
39#endif
40#ifndef WIFSIGNALED
41#define WIFSIGNALED(w) (((w) & 0xff) != 0x7f && ((w) & 0xff) != 0)
42#endif
43#ifndef WIFEXITED
44#define WIFEXITED(w) (((w) & 0xff) == 0)
45#endif
46
47#ifndef WSTOPSIG
48#define WSTOPSIG(w) (((w) >> 8) & 0xff)
49#endif
50#ifndef WTERMSIG
51#define WTERMSIG(w) ((w) & 0x7f)
52#endif
53#ifndef WEXITSTATUS
54#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
55#endif
56
57#if __STDC__
58#define P_(s) s
59#else
60#define P_(s) ()
61#endif
62
63#include <ctype.h>
64
65#if !defined (isascii) || defined (STDC_HEADERS)
66#ifdef isascii
67#undef isascii
68#endif
69#define isascii(c) 1
70#endif
71
72#ifdef isblank
73#define ISBLANK(c) (isascii (c) && isblank (c))
74#else
75#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
76#endif
77
78#define ISSPACE(c) (ISBLANK (c) || (c) == '\n' || (c) == '\r' \
79 || (c) == '\f' || (c) == '\v')
80
81#include <stdio.h>
82#include <errno.h> 32#include <errno.h>
83#include <getopt.h> 33#include <stdlib.h>
84
85#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
86#include <string.h> 34#include <string.h>
87#if !defined(STDC_HEADERS) 35#include <stdio.h>
88#include <memory.h> 36#include <getopt.h>
89#endif
90#else
91#include <strings.h>
92#define memcpy(dest, source, count) (bcopy((source), (dest), (count)))
93#endif
94
95#ifndef _POSIX_SOURCE
96#include <sys/param.h>
97#endif
98
99#ifdef HAVE_LIMITS_H
100#include <limits.h>
101#endif
102
103#ifndef LONG_MAX
104#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
105#endif
106
107#ifdef HAVE_UNISTD_H
108#include <unistd.h>
109#endif
110
111#include <signal.h>
112
113#if !defined(SIGCHLD) && defined(SIGCLD)
114#define SIGCHLD SIGCLD
115#endif
116
117/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
118 We try to make it as large as possible. */
119#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
120#define ARG_MAX sysconf (_SC_ARG_MAX)
121#endif
122#ifndef ARG_MAX
123#define ARG_MAX NCARGS
124#endif
125
126/* States for read_line. */
127#define NORM 0
128#define SPACE 1
129#define QUOTE 2
130#define BACKSLASH 3
131 37
132#ifdef STDC_HEADERS 38#ifndef MAX_ARGLINE
133#include <stdlib.h> 39# define MAX_ARGLINE 1023
134#else
135extern int errno;
136#endif 40#endif
137 41#ifndef min
138/* Return nonzero if S is the EOF string. */ 42# define min(a,b) ((a) < (b) ? (a) : (b))
139#define EOF_STR(s) (eof_str && *eof_str == *s && !strcmp (eof_str, s))
140
141extern char **environ;
142
143/* Not char because of type promotion; NeXT gcc can't handle it. */
144typedef int boolean;
145#define true 1
146#define false 0
147
148#if __STDC__
149#define VOID void
150#else
151#define VOID char
152#endif 43#endif
153 44
154VOID *xmalloc P_ ((size_t n)); 45char outlin[MAX_ARGLINE];
155VOID *xrealloc P_ ((VOID * p, size_t n)); 46char inlin[MAX_ARGLINE];
156 47char startlin[MAX_ARGLINE];
157/* The name this program was run with. */ 48char *ending = NULL;
158char *program_name; 49char traceflag = 0;
159
160/* Buffer for reading arguments from stdin. */
161static char *linebuf;
162
163/* Line number in stdin since the last command was executed. */
164static int lineno = 0;
165
166/* If nonzero, then instead of putting the args from stdin at
167 the end of the command argument list, they are each stuck into the
168 initial args, replacing each occurrence of the `replace_pat' in the
169 initial args. */
170static char *replace_pat = NULL;
171
172/* The length of `replace_pat'. */
173static size_t rplen = 0;
174
175/* If nonzero, when this string is read on stdin it is treated as
176 end of file.
177 I don't like this - it should default to NULL. */
178static char *eof_str = "_";
179
180/* If nonzero, the maximum number of nonblank lines from stdin to use
181 per command line. */
182static long lines_per_exec = 0;
183
184/* The maximum number of arguments to use per command line. */
185static long args_per_exec = 1024;
186
187/* If true, exit if lines_per_exec or args_per_exec is exceeded. */
188static boolean exit_if_size_exceeded = false;
189
190/* The maximum number of characters that can be used per command line. */
191static long arg_max;
192
193/* Storage for elements of `cmd_argv'. */
194static char *argbuf;
195
196/* The list of args being built. */
197static char **cmd_argv = NULL;
198
199/* Number of elements allocated for `cmd_argv'. */
200static int cmd_argv_alloc = 0;
201
202/* Number of valid elements in `cmd_argv'. */
203static int cmd_argc = 0;
204 50
205/* Number of chars being used in `cmd_argv'. */ 51int xargs_main(int ac, char **av)
206static int cmd_argv_chars = 0;
207
208/* Number of initial arguments given on the command line. */
209static int initial_argc = 0;
210
211/* Number of chars in the initial args. */
212static int initial_argv_chars = 0;
213
214/* true when building up initial arguments in `cmd_argv'. */
215static boolean initial_args = true;
216
217/* If nonzero, the maximum number of child processes that can be running
218 at once. */
219static int proc_max = 1;
220
221/* Total number of child processes that have been executed. */
222static int procs_executed = 0;
223
224/* The number of elements in `pids'. */
225static int procs_executing = 0;
226
227/* List of child processes currently executing. */
228static pid_t *pids = NULL;
229
230/* The number of allocated elements in `pids'. */
231static int pids_alloc = 0;
232
233/* Exit status; nonzero if any child process exited with a
234 status of 1-125. */
235static int child_error = 0;
236
237/* If true, print each command on stderr before executing it. */
238static boolean print_command = false;
239
240/* If true, query the user before executing each command, and only
241 execute the command if the user responds affirmatively. */
242static boolean query_before_executing = false;
243
244static struct option const longopts[] =
245{
246 {"null", no_argument, NULL, '0'},
247 {"eof", optional_argument, NULL, 'e'},
248 {"replace", optional_argument, NULL, 'i'},
249 {"max-lines", optional_argument, NULL, 'l'},
250 {"max-args", required_argument, NULL, 'n'},
251 {"interactive", no_argument, NULL, 'p'},
252 {"no-run-if-empty", no_argument, NULL, 'r'},
253 {"max-chars", required_argument, NULL, 's'},
254 {"verbose", no_argument, NULL, 't'},
255 {"exit", no_argument, NULL, 'x'},
256 {"max-procs", required_argument, NULL, 'P'},
257 {"help", no_argument, NULL, 'h'},
258 {NULL, no_argument, NULL, 0}
259};
260
261static int read_line P_ ((void));
262static int read_string P_ ((void));
263static void do_insert P_ ((char *arg, size_t arglen, size_t lblen));
264static void push_arg P_ ((char *arg, size_t len));
265static boolean print_args P_ ((boolean ask));
266static void do_exec P_ ((void));
267static void add_proc P_ ((pid_t pid));
268static void wait_for_proc P_ ((boolean all));
269static long parse_num P_ ((char *str, int option, long min, long max));
270static long env_size P_ ((char **envp));
271
272int xargs_main (argc, argv)
273 int argc;
274 char **argv;
275{ 52{
276 int optc; 53 int outlen, inlen, startlen, endlen=0, i;
277 int always_run_command = 1; 54 char errflg = 0;
278 long orig_arg_max; 55 int maxlin = MAX_ARGLINE;
279 char *default_cmd = "/bin/echo"; 56
280 int (*read_args) P_ ((void)) = read_line; 57 while ((i = getopt(ac, av, "tl:e:")) != EOF)
281 58 switch (i) {
282 program_name = argv[0]; 59 case 't': traceflag = 1; break;
283 60 case 'l': maxlin = min(MAX_ARGLINE, atoi(optarg)); break;
284 orig_arg_max = ARG_MAX; 61 case 'e': ending = optarg; break;
285 if (orig_arg_max == -1) 62 case '?': errflg++; break;
286 orig_arg_max = LONG_MAX; 63 }
287 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048. */ 64 if (errflg) {
288 arg_max = orig_arg_max; 65 fprintf(stderr, USAGE);
289 66 exit(2);
290 /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which 67 }
291 have it at 1 meg). Things will work fine with a large ARG_MAX but it 68
292 will probably hurt the system more than it needs to; an array of this 69 startlin[0] = 0;
293 size is allocated. */ 70 if (optind == ac) {
294 if (arg_max > 20 * 1024) 71 strcat(startlin, "echo ");
295 arg_max = 20 * 1024; 72 }
296 73 else for ( ; optind < ac; optind++) {
297 /* Take the size of the environment into account. */ 74 strcat(startlin, av[optind]);
298 arg_max -= env_size (environ); 75 strcat(startlin, " ");
299 if (arg_max <= 0) 76 }
300 fatalError("environment is too large for exec"); 77 startlen = strlen(startlin);
301 78 if (ending) endlen = strlen(ending);
302 while ((optc = getopt_long (argc, argv, "+0e::i::l::n:prs:txP:", 79 maxlin = maxlin - 1 - endlen; /* Pre-compute */
303 longopts, (int *) 0)) != -1) 80
304 { 81 strcpy(outlin, startlin);
305 switch (optc) 82 outlen = startlen;
306 { 83
307 case '0': 84 while (gets(inlin) != NULL) {
308 read_args = read_string; 85 inlen = strlen(inlin);
309 break; 86 if (maxlin <= (outlen + inlen)) {
310 87 if (outlen == startlen) {
311 case 'e': 88 fprintf(stderr, "%s: Line length too short to process '%s'\n",
312 if (optarg) 89 av[0], inlin);
313 eof_str = optarg; 90 exit(3);
314 else 91 }
315 eof_str = 0; 92 if (ending) strcat(outlin, ending);
316 break; 93 if (traceflag) fputs(outlin,stderr);
317 94 errno = 0;
318 case 'h': 95 if (0 != system(outlin)) {
319 usage (xargs_usage); 96 if (errno != 0) perror("xargs");
320 97 exit(1);
321 case 'i': 98 }
322 if (optarg) 99 strcpy(outlin, startlin);
323 replace_pat = optarg; 100 outlen = startlen;
324 else 101 }
325 replace_pat = "{}"; 102 strcat(outlin, inlin);
326 /* -i excludes -n -l. */ 103 strcat(outlin, " ");
327 args_per_exec = 0; 104 outlen = outlen + inlen + 1;
328 lines_per_exec = 0; 105 }
329 break; 106 if (outlen != startlen) {
330 107 if (ending) strcat(outlin, ending);
331 case 'l': 108 if (traceflag) fputs(outlin,stderr);
332 if (optarg) 109 errno = 0;
333 lines_per_exec = parse_num (optarg, 'l', 1L, -1L); 110 if (0 != system(outlin)) {
334 else 111 if (errno != 0) perror("xargs");
335 lines_per_exec = 1; 112 exit(1);
336 /* -l excludes -i -n. */ 113 }
337 args_per_exec = 0; 114 }
338 replace_pat = NULL; 115 return 0;
339 break;
340
341 case 'n':
342 args_per_exec = parse_num (optarg, 'n', 1L, -1L);
343 /* -n excludes -i -l. */
344 lines_per_exec = 0;
345 replace_pat = NULL;
346 break;
347
348 case 's':
349 arg_max = parse_num (optarg, 's', 1L, orig_arg_max);
350 break;
351
352 case 't':
353 print_command = true;
354 break;
355
356 case 'x':
357 exit_if_size_exceeded = true;
358 break;
359
360 case 'p':
361 query_before_executing = true;
362 print_command = true;
363 break;
364
365 case 'r':
366 always_run_command = 0;
367 break;
368
369 case 'P':
370 proc_max = parse_num (optarg, 'P', 0L, -1L);
371 break;
372
373 default:
374 usage (xargs_usage);
375 }
376 }
377
378 if (replace_pat || lines_per_exec)
379 exit_if_size_exceeded = true;
380
381 if (optind == argc)
382 {
383 optind = 0;
384 argc = 1;
385 argv = &default_cmd;
386 }
387
388 linebuf = (char *) xmalloc (arg_max + 1);
389 argbuf = (char *) xmalloc (arg_max + 1);
390
391 /* Make sure to listen for the kids. */
392 signal (SIGCHLD, SIG_DFL);
393
394 if (!replace_pat)
395 {
396 for (; optind < argc; optind++)
397 push_arg (argv[optind], strlen (argv[optind]) + 1);
398 initial_args = false;
399 initial_argc = cmd_argc;
400 initial_argv_chars = cmd_argv_chars;
401
402 while ((*read_args) () != -1)
403 if (lines_per_exec && lineno >= lines_per_exec)
404 {
405 do_exec ();
406 lineno = 0;
407 }
408
409 /* SYSV xargs seems to do at least one exec, even if the
410 input is empty. */
411 if (cmd_argc != initial_argc
412 || (always_run_command && procs_executed == 0))
413 do_exec ();
414 }
415 else
416 {
417 int i;
418 size_t len;
419 size_t *arglen = (size_t *) xmalloc (sizeof (size_t) * argc);
420
421 for (i = optind; i < argc; i++)
422 arglen[i] = strlen(argv[i]);
423 rplen = strlen (replace_pat);
424 while ((len = (*read_args) ()) != -1)
425 {
426 /* Don't do insert on the command name. */
427 push_arg (argv[optind], arglen[optind] + 1);
428 len--;
429 for (i = optind + 1; i < argc; i++)
430 do_insert (argv[i], arglen[i], len);
431 do_exec ();
432 }
433 }
434
435 wait_for_proc (true);
436 exit (child_error);
437} 116}
438
439/* Read a line of arguments from stdin and add them to the list of
440 arguments to pass to the command. Ignore blank lines and initial blanks.
441 Single and double quotes and backslashes quote metacharacters and blanks
442 as they do in the shell.
443 Return -1 if eof (either physical or logical) is reached,
444 otherwise the length of the last string read (including the null). */
445
446static int
447read_line ()
448{
449 static boolean eof = false;
450 /* Start out in mode SPACE to always strip leading spaces (even with -i). */
451 int state = SPACE; /* The type of character we last read. */
452 int prevc; /* The previous value of c. */
453 int quotc = 0; /* The last quote character read. */
454 int c = EOF;
455 boolean first = true; /* true if reading first arg on line. */
456 int len;
457 char *p = linebuf;
458 /* Including the NUL, the args must not grow past this point. */
459 char *endbuf = linebuf + arg_max - initial_argv_chars - 1;
460
461 if (eof)
462 return -1;
463 while (1)
464 {
465 prevc = c;
466 c = getc (stdin);
467 if (c == EOF)
468 {
469 /* COMPAT: SYSV seems to ignore stuff on a line that
470 ends without a \n; we don't. */
471 eof = true;
472 if (p == linebuf)
473 return -1;
474 *p++ = '\0';
475 len = p - linebuf;
476 /* FIXME we don't check for unterminated quotes here. */
477 if (first && EOF_STR (linebuf))
478 return -1;
479 if (!replace_pat)
480 push_arg (linebuf, len);
481 return len;
482 }
483 switch (state)
484 {
485 case SPACE:
486 if (ISSPACE (c))
487 continue;
488 state = NORM;
489 /* aaahhhh.... */
490
491 case NORM:
492 if (c == '\n')
493 {
494 if (!ISBLANK (prevc))
495 lineno++; /* For -l. */
496 if (p == linebuf)
497 {
498 /* Blank line. */
499 state = SPACE;
500 continue;
501 }
502 *p++ = '\0';
503 len = p - linebuf;
504 if (EOF_STR (linebuf))
505 {
506 eof = true;
507 return first ? -1 : len;
508 }
509 if (!replace_pat)
510 push_arg (linebuf, len);
511 return len;
512 }
513 if (!replace_pat && ISSPACE (c))
514 {
515 *p++ = '\0';
516 len = p - linebuf;
517 if (EOF_STR (linebuf))
518 {
519 eof = true;
520 return first ? -1 : len;
521 }
522 push_arg (linebuf, len);
523 p = linebuf;
524 state = SPACE;
525 first = false;
526 continue;
527 }
528 switch (c)
529 {
530 case '\\':
531 state = BACKSLASH;
532 continue;
533
534 case '\'':
535 case '"':
536 state = QUOTE;
537 quotc = c;
538 continue;
539 }
540 break;
541
542 case QUOTE:
543 if (c == '\n')
544 fatalError ("unmatched %s quote", quotc == '"' ? "double" : "single");
545 if (c == quotc)
546 {
547 state = NORM;
548 continue;
549 }
550 break;
551
552 case BACKSLASH:
553 state = NORM;
554 break;
555 }
556 if (p >= endbuf)
557 fatalError ("argument line too long");
558 *p++ = c;
559 }
560}
561
562/* Read a null-terminated string from stdin and add it to the list of
563 arguments to pass to the command.
564 Return -1 if eof (either physical or logical) is reached,
565 otherwise the length of the string read (including the null). */
566
567static int
568read_string ()
569{
570 static boolean eof = false;
571 int len;
572 char *p = linebuf;
573 /* Including the NUL, the args must not grow past this point. */
574 char *endbuf = linebuf + arg_max - initial_argv_chars - 1;
575
576 if (eof)
577 return -1;
578 while (1)
579 {
580 int c = getc (stdin);
581 if (c == EOF)
582 {
583 eof = true;
584 if (p == linebuf)
585 return -1;
586 *p++ = '\0';
587 len = p - linebuf;
588 if (!replace_pat)
589 push_arg (linebuf, len);
590 return len;
591 }
592 if (c == '\0')
593 {
594 lineno++; /* For -l. */
595 *p++ = '\0';
596 len = p - linebuf;
597 if (!replace_pat)
598 push_arg (linebuf, len);
599 return len;
600 }
601 if (p >= endbuf)
602 fatalError ("argument line too long");
603 *p++ = c;
604 }
605}
606
607/* Replace all instances of `replace_pat' in ARG with `linebuf',
608 and add the resulting string to the list of arguments for the command
609 to execute.
610 ARGLEN is the length of ARG, not including the null.
611 LBLEN is the length of `linebuf', not including the null.
612
613 COMPAT: insertions on the SYSV version are limited to 255 chars per line,
614 and a max of 5 occurences of replace_pat in the initial-arguments.
615 Those restrictions do not exist here. */
616
617static void
618do_insert (arg, arglen, lblen)
619 char *arg;
620 size_t arglen;
621 size_t lblen;
622{
623 /* Temporary copy of each arg with the replace pattern replaced by the
624 real arg. */
625 static char *insertbuf;
626 char *p;
627 int bytes_left = arg_max - 1; /* Bytes left on the command line. */
628
629 if (!insertbuf)
630 insertbuf = (char *) xmalloc (arg_max + 1);
631 p = insertbuf;
632
633 do
634 {
635 size_t len; /* Length in ARG before `replace_pat'. */
636 char *s = strstr (arg, replace_pat);
637 if (s)
638 len = s - arg;
639 else
640 len = arglen;
641 bytes_left -= len;
642 if (bytes_left <= 0)
643 break;
644
645 strncpy (p, arg, len);
646 p += len;
647 arg += len;
648 arglen -= len;
649
650 if (s)
651 {
652 bytes_left -= lblen;
653 if (bytes_left <= 0)
654 break;
655 strcpy (p, linebuf);
656 arg += rplen;
657 arglen -= rplen;
658 p += lblen;
659 }
660 }
661 while (*arg);
662 if (*arg)
663 fatalError ("command too long");
664 *p++ = '\0';
665 push_arg (insertbuf, p - insertbuf);
666}
667
668/* Add ARG to the end of the list of arguments `cmd_argv' to pass
669 to the command.
670 LEN is the length of ARG, including the terminating null.
671 If this brings the list up to its maximum size, execute the command. */
672
673static void
674push_arg (arg, len)
675 char *arg;
676 size_t len;
677{
678 if (arg)
679 {
680 if (cmd_argv_chars + len > arg_max)
681 {
682 if (initial_args || cmd_argc == initial_argc)
683 fatalError ("can not fit single argument within argument list size limit");
684 if (replace_pat
685 || (exit_if_size_exceeded &&
686 (lines_per_exec || args_per_exec)))
687 fatalError ("argument list too long");
688 do_exec ();
689 }
690 if (!initial_args && args_per_exec &&
691 cmd_argc - initial_argc == args_per_exec)
692 do_exec ();
693 }
694
695 if (cmd_argc >= cmd_argv_alloc)
696 {
697 if (!cmd_argv)
698 {
699 cmd_argv_alloc = 64;
700 cmd_argv = (char **) xmalloc (sizeof (char *) * cmd_argv_alloc);
701 }
702 else
703 {
704 cmd_argv_alloc *= 2;
705 cmd_argv = (char **) xrealloc (cmd_argv,
706 sizeof (char *) * cmd_argv_alloc);
707 }
708 }
709
710 if (!arg)
711 cmd_argv[cmd_argc++] = NULL;
712 else
713 {
714 cmd_argv[cmd_argc++] = argbuf + cmd_argv_chars;
715 strcpy (argbuf + cmd_argv_chars, arg);
716 cmd_argv_chars += len;
717 }
718}
719
720/* Print the arguments of the command to execute.
721 If ASK is nonzero, prompt the user for a response, and
722 if the user responds affirmatively, return true;
723 otherwise, return false. */
724
725static boolean
726print_args (ask)
727 boolean ask;
728{
729 int i;
730
731 for (i = 0; i < cmd_argc - 1; i++)
732 fprintf (stderr, "%s ", cmd_argv[i]);
733 if (ask)
734 {
735 static FILE *tty_stream;
736 int c, savec;
737
738 if (!tty_stream)
739 {
740 tty_stream = fopen ("/dev/tty", "r");
741 if (!tty_stream)
742 fatalError (" Could not open /dev/tty");
743 }
744 fputs ("?...", stderr);
745 fflush (stderr);
746 c = savec = getc (tty_stream);
747 while (c != EOF && c != '\n')
748 c = getc (tty_stream);
749 if (savec == 'y' || savec == 'Y')
750 return true;
751 }
752 else
753 putc ('\n', stderr);
754
755 return false;
756}
757
758/* Execute the command that has been built in `cmd_argv'. This may involve
759 waiting for processes that were previously executed. */
760
761static void
762do_exec ()
763{
764 pid_t child;
765
766 push_arg ((char *) NULL, 0); /* Null terminate the arg list. */
767 if (!query_before_executing || print_args (true))
768 {
769 if (proc_max && procs_executing >= proc_max)
770 wait_for_proc (false);
771 if (!query_before_executing && print_command)
772 print_args (false);
773 /* If we run out of processes, wait for a child to return and
774 try again. */
775 while ((child = fork ()) < 0 && errno == EAGAIN && procs_executing)
776 wait_for_proc (false);
777 switch (child)
778 {
779 case -1:
780 fatalError ("cannot fork");
781
782 case 0: /* Child. */
783 execvp (cmd_argv[0], cmd_argv);
784 errorMsg ("failed to exec '%s'", cmd_argv[0]);
785 _exit (errno == ENOENT ? 127 : 126);
786 }
787 add_proc (child);
788 }
789
790 cmd_argc = initial_argc;
791 cmd_argv_chars = initial_argv_chars;
792}
793
794/* Add the process with id PID to the list of processes that have
795 been executed. */
796
797static void
798add_proc (pid)
799 pid_t pid;
800{
801 int i;
802
803 /* Find an empty slot. */
804 for (i = 0; i < pids_alloc && pids[i]; i++)
805 ;
806 if (i == pids_alloc)
807 {
808 if (pids_alloc == 0)
809 {
810 pids_alloc = proc_max ? proc_max : 64;
811 pids = (pid_t *) xmalloc (sizeof (pid_t) * pids_alloc);
812 }
813 else
814 {
815 pids_alloc *= 2;
816 pids = (pid_t *) xrealloc (pids,
817 sizeof (pid_t) * pids_alloc);
818 }
819 memset (&pids[i], '\0', sizeof (pid_t) * (pids_alloc - i));
820 }
821 pids[i] = pid;
822 procs_executing++;
823 procs_executed++;
824}
825
826/* If ALL is true, wait for all child processes to finish;
827 otherwise, wait for one child process to finish.
828 Remove the processes that finish from the list of executing processes. */
829
830static void
831wait_for_proc (all)
832 boolean all;
833{
834 while (procs_executing)
835 {
836 int i, status;
837
838 do
839 {
840 pid_t pid;
841
842 pid = wait (&status);
843 if (pid < 0)
844 fatalError ("error waiting for child process");
845
846 /* Find the entry in `pids' for the child process
847 that exited. */
848 for (i = 0; i < pids_alloc && pid != pids[i]; i++)
849 ;
850 }
851 while (i == pids_alloc); /* A child died that we didn't start? */
852
853 /* Remove the child from the list. */
854 pids[i] = 0;
855 procs_executing--;
856
857 if (WEXITSTATUS (status) == 126 || WEXITSTATUS (status) == 127)
858 exit (WEXITSTATUS (status)); /* Can't find or run the command. */
859 if (WEXITSTATUS (status) == 255)
860 fatalError ( "%s: exited with status 255; aborting", cmd_argv[0]);
861 if (WIFSTOPPED (status))
862 fatalError ( "%s: stopped by signal %d", cmd_argv[0], WSTOPSIG (status));
863 if (WIFSIGNALED (status))
864 fatalError ("%s: terminated by signal %d", cmd_argv[0], WTERMSIG (status));
865 if (WEXITSTATUS (status) != 0)
866 child_error = 123;
867
868 if (!all)
869 break;
870 }
871}
872
873/* Return the value of the number represented in STR.
874 OPTION is the command line option to which STR is the argument.
875 If the value does not fall within the boundaries MIN and MAX,
876 Print an error message mentioning OPTION and exit. */
877
878static long
879parse_num (str, option, min, max)
880 char *str;
881 int option;
882 long min;
883 long max;
884{
885 char *eptr;
886 long val;
887
888 val = strtol (str, &eptr, 10);
889 if (eptr == str || *eptr)
890 {
891 fprintf (stderr, "%s: invalid number for -%c option\n",
892 program_name, option);
893 usage (xargs_usage);
894 }
895 else if (val < min)
896 {
897 fprintf (stderr, "%s: value for -%c option must be >= %ld\n",
898 program_name, option, min);
899 usage (xargs_usage);
900 }
901 else if (max >= 0 && val > max)
902 {
903 fprintf (stderr, "%s: value for -%c option must be < %ld\n",
904 program_name, option, max);
905 usage (xargs_usage);
906 }
907 return val;
908}
909
910/* Return how much of ARG_MAX is used by the environment. */
911
912static long
913env_size (envp)
914 char **envp;
915{
916 long len = 0;
917
918 while (*envp)
919 len += strlen (*envp++) + 1;
920
921 return len;
922}
923
diff --git a/usage.c b/usage.c
index 8e0247941..236bc9460 100644
--- a/usage.c
+++ b/usage.c
@@ -592,6 +592,9 @@ const char ls_usage[] =
592#ifdef BB_FEATURE_LS_FILETYPES 592#ifdef BB_FEATURE_LS_FILETYPES
593 "p" 593 "p"
594#endif 594#endif
595#ifdef BB_FEATURE_LS_FOLLOWLINKS
596 "L"
597#endif
595#ifdef BB_FEATURE_LS_RECURSIVE 598#ifdef BB_FEATURE_LS_RECURSIVE
596 "R" 599 "R"
597#endif 600#endif
@@ -640,6 +643,9 @@ const char ls_usage[] =
640#ifdef BB_FEATURE_LS_FILETYPES 643#ifdef BB_FEATURE_LS_FILETYPES
641 "\t-p\tappend indicator (one of /=@|) to entries\n" 644 "\t-p\tappend indicator (one of /=@|) to entries\n"
642#endif 645#endif
646#ifdef BB_FEATURE_LS_FOLLOWLINKS
647 "\t-L\tlist entries pointed to by symbolic links\n"
648#endif
643#ifdef BB_FEATURE_LS_RECURSIVE 649#ifdef BB_FEATURE_LS_RECURSIVE
644 "\t-R\tlist subdirectories recursively\n" 650 "\t-R\tlist subdirectories recursively\n"
645#endif 651#endif
@@ -1433,14 +1439,15 @@ const char whoami_usage[] =
1433#endif 1439#endif
1434 1440
1435#if defined BB_XARGS 1441#if defined BB_XARGS
1436const char xargs_usage[] = 1442const char xargs_usage[] = "xargs [OPTIONS] [COMMAND] [ARGS...]\n"
1437 "xargs [-0prtx] [-e[eof-str]] [-i[replace-str]] [-l[max-lines]]\n" 1443#ifndef BB_FEATURE_TRIVIAL_HELP
1438 "[-n max-args] [-s max-chars] [-P max-procs] [--null] [--eof[=eof-str]]\n" 1444 "\nExecutes COMMAND on every item given by standard input.\n\n"
1439 "[--replace[=replace-str]] [--max-lines[=max-lines]] [--interactive]\n" 1445 "Options:\n"
1440 "[--max-chars=max-chars] [--verbose] [--exit] [--max-procs=max-procs]\n" 1446 "\t-t\tPrint the command just before it is run\n"
1441 "[--max-args=max-args] [--no-run-if-empty] [--help]\n" 1447 "\t-l LEN\tUse LEN as maximum line length (default 490, max 1023)\n"
1442 "[command [initial-arguments]]\n" 1448 "\t-e ENDING\tAppend ENDING to the command before executing it.\n"
1443 "\nBuild and execute command on lines from standard input.\n"; 1449#endif
1450 ;
1444#endif 1451#endif
1445 1452
1446#if defined BB_YES 1453#if defined BB_YES
diff --git a/xargs.c b/xargs.c
index adf1f134c..be1fada78 100644
--- a/xargs.c
+++ b/xargs.c
@@ -1,923 +1,116 @@
1/* xargs for busybox -- using GNU xargs till we can get something 1/* minix xargs - Make and execute commands
2 * better. minix xargs is a bit smaller... */ 2 * Author: Ian Nicholls: 1 Mar 90 */
3
4/*
5 * xargs - Accept words from stdin until, combined with the arguments
6 * given on the command line, just fit into the command line limit.
7 * Then, execute the result.
8 * e.g. ls | xargs compress
9 * find . -name '*.s' -print | xargs ar qv libc.a
10 *
11 * flags: -t Print the command just before it is run
12 * -l len Use len as maximum line length (default 490, max 1023)
13 * -e ending Append ending to the command before executing it.
14 *
15 * Exits with: 0 No errors.
16 * 1 If any system(3) call returns a nonzero status.
17 * 2 Usage error
18 * 3 Line length too short to contain some single argument.
19 *
20 * Examples: xargs ar qv libc.a < liborder # Create a new libc.a
21 * find . -name '*.s' -print | xargs rm # Remove all .s files
22 * find . -type f ! -name '*.Z' \ # Compress old files.
23 * -atime +60 -print | xargs compress -v
24 *
25 * Bugs: If the command contains unquoted wildflags, then the system(3) call
26 * call may expand this to larger than the maximum line size.
27 * The command is not executed if nothing was read from stdin.
28 * xargs may give up too easily when the command returns nonzero.
29 */
30#define USAGE "usage: xargs [-t] [-l len] [-e endargs] command [args...]\n"
3 31
4/* xargs -- build and execute command lines from standard input
5 Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21/* Written by Mike Rendell <michael@cs.mun.ca>
22 and David MacKenzie <djm@gnu.ai.mit.edu>. */
23
24#include "internal.h"
25
26#define HAVE_STRING_H 1
27#define HAVE_SYS_WAIT_H 1
28#define HAVE_UNISTD_H 1
29#define HAVE_LIMITS_H 1
30#define STDC_HEADERS 1
31
32#include <sys/types.h> /* For pid_t. */
33#if HAVE_SYS_WAIT_H
34#include <sys/wait.h>
35#endif
36
37#ifndef WIFSTOPPED
38#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
39#endif
40#ifndef WIFSIGNALED
41#define WIFSIGNALED(w) (((w) & 0xff) != 0x7f && ((w) & 0xff) != 0)
42#endif
43#ifndef WIFEXITED
44#define WIFEXITED(w) (((w) & 0xff) == 0)
45#endif
46
47#ifndef WSTOPSIG
48#define WSTOPSIG(w) (((w) >> 8) & 0xff)
49#endif
50#ifndef WTERMSIG
51#define WTERMSIG(w) ((w) & 0x7f)
52#endif
53#ifndef WEXITSTATUS
54#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
55#endif
56
57#if __STDC__
58#define P_(s) s
59#else
60#define P_(s) ()
61#endif
62
63#include <ctype.h>
64
65#if !defined (isascii) || defined (STDC_HEADERS)
66#ifdef isascii
67#undef isascii
68#endif
69#define isascii(c) 1
70#endif
71
72#ifdef isblank
73#define ISBLANK(c) (isascii (c) && isblank (c))
74#else
75#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
76#endif
77
78#define ISSPACE(c) (ISBLANK (c) || (c) == '\n' || (c) == '\r' \
79 || (c) == '\f' || (c) == '\v')
80
81#include <stdio.h>
82#include <errno.h> 32#include <errno.h>
83#include <getopt.h> 33#include <stdlib.h>
84
85#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
86#include <string.h> 34#include <string.h>
87#if !defined(STDC_HEADERS) 35#include <stdio.h>
88#include <memory.h> 36#include <getopt.h>
89#endif
90#else
91#include <strings.h>
92#define memcpy(dest, source, count) (bcopy((source), (dest), (count)))
93#endif
94
95#ifndef _POSIX_SOURCE
96#include <sys/param.h>
97#endif
98
99#ifdef HAVE_LIMITS_H
100#include <limits.h>
101#endif
102
103#ifndef LONG_MAX
104#define LONG_MAX (~(1 << (sizeof (long) * 8 - 1)))
105#endif
106
107#ifdef HAVE_UNISTD_H
108#include <unistd.h>
109#endif
110
111#include <signal.h>
112
113#if !defined(SIGCHLD) && defined(SIGCLD)
114#define SIGCHLD SIGCLD
115#endif
116
117/* COMPAT: SYSV version defaults size (and has a max value of) to 470.
118 We try to make it as large as possible. */
119#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
120#define ARG_MAX sysconf (_SC_ARG_MAX)
121#endif
122#ifndef ARG_MAX
123#define ARG_MAX NCARGS
124#endif
125
126/* States for read_line. */
127#define NORM 0
128#define SPACE 1
129#define QUOTE 2
130#define BACKSLASH 3
131 37
132#ifdef STDC_HEADERS 38#ifndef MAX_ARGLINE
133#include <stdlib.h> 39# define MAX_ARGLINE 1023
134#else
135extern int errno;
136#endif 40#endif
137 41#ifndef min
138/* Return nonzero if S is the EOF string. */ 42# define min(a,b) ((a) < (b) ? (a) : (b))
139#define EOF_STR(s) (eof_str && *eof_str == *s && !strcmp (eof_str, s))
140
141extern char **environ;
142
143/* Not char because of type promotion; NeXT gcc can't handle it. */
144typedef int boolean;
145#define true 1
146#define false 0
147
148#if __STDC__
149#define VOID void
150#else
151#define VOID char
152#endif 43#endif
153 44
154VOID *xmalloc P_ ((size_t n)); 45char outlin[MAX_ARGLINE];
155VOID *xrealloc P_ ((VOID * p, size_t n)); 46char inlin[MAX_ARGLINE];
156 47char startlin[MAX_ARGLINE];
157/* The name this program was run with. */ 48char *ending = NULL;
158char *program_name; 49char traceflag = 0;
159
160/* Buffer for reading arguments from stdin. */
161static char *linebuf;
162
163/* Line number in stdin since the last command was executed. */
164static int lineno = 0;
165
166/* If nonzero, then instead of putting the args from stdin at
167 the end of the command argument list, they are each stuck into the
168 initial args, replacing each occurrence of the `replace_pat' in the
169 initial args. */
170static char *replace_pat = NULL;
171
172/* The length of `replace_pat'. */
173static size_t rplen = 0;
174
175/* If nonzero, when this string is read on stdin it is treated as
176 end of file.
177 I don't like this - it should default to NULL. */
178static char *eof_str = "_";
179
180/* If nonzero, the maximum number of nonblank lines from stdin to use
181 per command line. */
182static long lines_per_exec = 0;
183
184/* The maximum number of arguments to use per command line. */
185static long args_per_exec = 1024;
186
187/* If true, exit if lines_per_exec or args_per_exec is exceeded. */
188static boolean exit_if_size_exceeded = false;
189
190/* The maximum number of characters that can be used per command line. */
191static long arg_max;
192
193/* Storage for elements of `cmd_argv'. */
194static char *argbuf;
195
196/* The list of args being built. */
197static char **cmd_argv = NULL;
198
199/* Number of elements allocated for `cmd_argv'. */
200static int cmd_argv_alloc = 0;
201
202/* Number of valid elements in `cmd_argv'. */
203static int cmd_argc = 0;
204 50
205/* Number of chars being used in `cmd_argv'. */ 51int xargs_main(int ac, char **av)
206static int cmd_argv_chars = 0;
207
208/* Number of initial arguments given on the command line. */
209static int initial_argc = 0;
210
211/* Number of chars in the initial args. */
212static int initial_argv_chars = 0;
213
214/* true when building up initial arguments in `cmd_argv'. */
215static boolean initial_args = true;
216
217/* If nonzero, the maximum number of child processes that can be running
218 at once. */
219static int proc_max = 1;
220
221/* Total number of child processes that have been executed. */
222static int procs_executed = 0;
223
224/* The number of elements in `pids'. */
225static int procs_executing = 0;
226
227/* List of child processes currently executing. */
228static pid_t *pids = NULL;
229
230/* The number of allocated elements in `pids'. */
231static int pids_alloc = 0;
232
233/* Exit status; nonzero if any child process exited with a
234 status of 1-125. */
235static int child_error = 0;
236
237/* If true, print each command on stderr before executing it. */
238static boolean print_command = false;
239
240/* If true, query the user before executing each command, and only
241 execute the command if the user responds affirmatively. */
242static boolean query_before_executing = false;
243
244static struct option const longopts[] =
245{
246 {"null", no_argument, NULL, '0'},
247 {"eof", optional_argument, NULL, 'e'},
248 {"replace", optional_argument, NULL, 'i'},
249 {"max-lines", optional_argument, NULL, 'l'},
250 {"max-args", required_argument, NULL, 'n'},
251 {"interactive", no_argument, NULL, 'p'},
252 {"no-run-if-empty", no_argument, NULL, 'r'},
253 {"max-chars", required_argument, NULL, 's'},
254 {"verbose", no_argument, NULL, 't'},
255 {"exit", no_argument, NULL, 'x'},
256 {"max-procs", required_argument, NULL, 'P'},
257 {"help", no_argument, NULL, 'h'},
258 {NULL, no_argument, NULL, 0}
259};
260
261static int read_line P_ ((void));
262static int read_string P_ ((void));
263static void do_insert P_ ((char *arg, size_t arglen, size_t lblen));
264static void push_arg P_ ((char *arg, size_t len));
265static boolean print_args P_ ((boolean ask));
266static void do_exec P_ ((void));
267static void add_proc P_ ((pid_t pid));
268static void wait_for_proc P_ ((boolean all));
269static long parse_num P_ ((char *str, int option, long min, long max));
270static long env_size P_ ((char **envp));
271
272int xargs_main (argc, argv)
273 int argc;
274 char **argv;
275{ 52{
276 int optc; 53 int outlen, inlen, startlen, endlen=0, i;
277 int always_run_command = 1; 54 char errflg = 0;
278 long orig_arg_max; 55 int maxlin = MAX_ARGLINE;
279 char *default_cmd = "/bin/echo"; 56
280 int (*read_args) P_ ((void)) = read_line; 57 while ((i = getopt(ac, av, "tl:e:")) != EOF)
281 58 switch (i) {
282 program_name = argv[0]; 59 case 't': traceflag = 1; break;
283 60 case 'l': maxlin = min(MAX_ARGLINE, atoi(optarg)); break;
284 orig_arg_max = ARG_MAX; 61 case 'e': ending = optarg; break;
285 if (orig_arg_max == -1) 62 case '?': errflg++; break;
286 orig_arg_max = LONG_MAX; 63 }
287 orig_arg_max -= 2048; /* POSIX.2 requires subtracting 2048. */ 64 if (errflg) {
288 arg_max = orig_arg_max; 65 fprintf(stderr, USAGE);
289 66 exit(2);
290 /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which 67 }
291 have it at 1 meg). Things will work fine with a large ARG_MAX but it 68
292 will probably hurt the system more than it needs to; an array of this 69 startlin[0] = 0;
293 size is allocated. */ 70 if (optind == ac) {
294 if (arg_max > 20 * 1024) 71 strcat(startlin, "echo ");
295 arg_max = 20 * 1024; 72 }
296 73 else for ( ; optind < ac; optind++) {
297 /* Take the size of the environment into account. */ 74 strcat(startlin, av[optind]);
298 arg_max -= env_size (environ); 75 strcat(startlin, " ");
299 if (arg_max <= 0) 76 }
300 fatalError("environment is too large for exec"); 77 startlen = strlen(startlin);
301 78 if (ending) endlen = strlen(ending);
302 while ((optc = getopt_long (argc, argv, "+0e::i::l::n:prs:txP:", 79 maxlin = maxlin - 1 - endlen; /* Pre-compute */
303 longopts, (int *) 0)) != -1) 80
304 { 81 strcpy(outlin, startlin);
305 switch (optc) 82 outlen = startlen;
306 { 83
307 case '0': 84 while (gets(inlin) != NULL) {
308 read_args = read_string; 85 inlen = strlen(inlin);
309 break; 86 if (maxlin <= (outlen + inlen)) {
310 87 if (outlen == startlen) {
311 case 'e': 88 fprintf(stderr, "%s: Line length too short to process '%s'\n",
312 if (optarg) 89 av[0], inlin);
313 eof_str = optarg; 90 exit(3);
314 else 91 }
315 eof_str = 0; 92 if (ending) strcat(outlin, ending);
316 break; 93 if (traceflag) fputs(outlin,stderr);
317 94 errno = 0;
318 case 'h': 95 if (0 != system(outlin)) {
319 usage (xargs_usage); 96 if (errno != 0) perror("xargs");
320 97 exit(1);
321 case 'i': 98 }
322 if (optarg) 99 strcpy(outlin, startlin);
323 replace_pat = optarg; 100 outlen = startlen;
324 else 101 }
325 replace_pat = "{}"; 102 strcat(outlin, inlin);
326 /* -i excludes -n -l. */ 103 strcat(outlin, " ");
327 args_per_exec = 0; 104 outlen = outlen + inlen + 1;
328 lines_per_exec = 0; 105 }
329 break; 106 if (outlen != startlen) {
330 107 if (ending) strcat(outlin, ending);
331 case 'l': 108 if (traceflag) fputs(outlin,stderr);
332 if (optarg) 109 errno = 0;
333 lines_per_exec = parse_num (optarg, 'l', 1L, -1L); 110 if (0 != system(outlin)) {
334 else 111 if (errno != 0) perror("xargs");
335 lines_per_exec = 1; 112 exit(1);
336 /* -l excludes -i -n. */ 113 }
337 args_per_exec = 0; 114 }
338 replace_pat = NULL; 115 return 0;
339 break;
340
341 case 'n':
342 args_per_exec = parse_num (optarg, 'n', 1L, -1L);
343 /* -n excludes -i -l. */
344 lines_per_exec = 0;
345 replace_pat = NULL;
346 break;
347
348 case 's':
349 arg_max = parse_num (optarg, 's', 1L, orig_arg_max);
350 break;
351
352 case 't':
353 print_command = true;
354 break;
355
356 case 'x':
357 exit_if_size_exceeded = true;
358 break;
359
360 case 'p':
361 query_before_executing = true;
362 print_command = true;
363 break;
364
365 case 'r':
366 always_run_command = 0;
367 break;
368
369 case 'P':
370 proc_max = parse_num (optarg, 'P', 0L, -1L);
371 break;
372
373 default:
374 usage (xargs_usage);
375 }
376 }
377
378 if (replace_pat || lines_per_exec)
379 exit_if_size_exceeded = true;
380
381 if (optind == argc)
382 {
383 optind = 0;
384 argc = 1;
385 argv = &default_cmd;
386 }
387
388 linebuf = (char *) xmalloc (arg_max + 1);
389 argbuf = (char *) xmalloc (arg_max + 1);
390
391 /* Make sure to listen for the kids. */
392 signal (SIGCHLD, SIG_DFL);
393
394 if (!replace_pat)
395 {
396 for (; optind < argc; optind++)
397 push_arg (argv[optind], strlen (argv[optind]) + 1);
398 initial_args = false;
399 initial_argc = cmd_argc;
400 initial_argv_chars = cmd_argv_chars;
401
402 while ((*read_args) () != -1)
403 if (lines_per_exec && lineno >= lines_per_exec)
404 {
405 do_exec ();
406 lineno = 0;
407 }
408
409 /* SYSV xargs seems to do at least one exec, even if the
410 input is empty. */
411 if (cmd_argc != initial_argc
412 || (always_run_command && procs_executed == 0))
413 do_exec ();
414 }
415 else
416 {
417 int i;
418 size_t len;
419 size_t *arglen = (size_t *) xmalloc (sizeof (size_t) * argc);
420
421 for (i = optind; i < argc; i++)
422 arglen[i] = strlen(argv[i]);
423 rplen = strlen (replace_pat);
424 while ((len = (*read_args) ()) != -1)
425 {
426 /* Don't do insert on the command name. */
427 push_arg (argv[optind], arglen[optind] + 1);
428 len--;
429 for (i = optind + 1; i < argc; i++)
430 do_insert (argv[i], arglen[i], len);
431 do_exec ();
432 }
433 }
434
435 wait_for_proc (true);
436 exit (child_error);
437} 116}
438
439/* Read a line of arguments from stdin and add them to the list of
440 arguments to pass to the command. Ignore blank lines and initial blanks.
441 Single and double quotes and backslashes quote metacharacters and blanks
442 as they do in the shell.
443 Return -1 if eof (either physical or logical) is reached,
444 otherwise the length of the last string read (including the null). */
445
446static int
447read_line ()
448{
449 static boolean eof = false;
450 /* Start out in mode SPACE to always strip leading spaces (even with -i). */
451 int state = SPACE; /* The type of character we last read. */
452 int prevc; /* The previous value of c. */
453 int quotc = 0; /* The last quote character read. */
454 int c = EOF;
455 boolean first = true; /* true if reading first arg on line. */
456 int len;
457 char *p = linebuf;
458 /* Including the NUL, the args must not grow past this point. */
459 char *endbuf = linebuf + arg_max - initial_argv_chars - 1;
460
461 if (eof)
462 return -1;
463 while (1)
464 {
465 prevc = c;
466 c = getc (stdin);
467 if (c == EOF)
468 {
469 /* COMPAT: SYSV seems to ignore stuff on a line that
470 ends without a \n; we don't. */
471 eof = true;
472 if (p == linebuf)
473 return -1;
474 *p++ = '\0';
475 len = p - linebuf;
476 /* FIXME we don't check for unterminated quotes here. */
477 if (first && EOF_STR (linebuf))
478 return -1;
479 if (!replace_pat)
480 push_arg (linebuf, len);
481 return len;
482 }
483 switch (state)
484 {
485 case SPACE:
486 if (ISSPACE (c))
487 continue;
488 state = NORM;
489 /* aaahhhh.... */
490
491 case NORM:
492 if (c == '\n')
493 {
494 if (!ISBLANK (prevc))
495 lineno++; /* For -l. */
496 if (p == linebuf)
497 {
498 /* Blank line. */
499 state = SPACE;
500 continue;
501 }
502 *p++ = '\0';
503 len = p - linebuf;
504 if (EOF_STR (linebuf))
505 {
506 eof = true;
507 return first ? -1 : len;
508 }
509 if (!replace_pat)
510 push_arg (linebuf, len);
511 return len;
512 }
513 if (!replace_pat && ISSPACE (c))
514 {
515 *p++ = '\0';
516 len = p - linebuf;
517 if (EOF_STR (linebuf))
518 {
519 eof = true;
520 return first ? -1 : len;
521 }
522 push_arg (linebuf, len);
523 p = linebuf;
524 state = SPACE;
525 first = false;
526 continue;
527 }
528 switch (c)
529 {
530 case '\\':
531 state = BACKSLASH;
532 continue;
533
534 case '\'':
535 case '"':
536 state = QUOTE;
537 quotc = c;
538 continue;
539 }
540 break;
541
542 case QUOTE:
543 if (c == '\n')
544 fatalError ("unmatched %s quote", quotc == '"' ? "double" : "single");
545 if (c == quotc)
546 {
547 state = NORM;
548 continue;
549 }
550 break;
551
552 case BACKSLASH:
553 state = NORM;
554 break;
555 }
556 if (p >= endbuf)
557 fatalError ("argument line too long");
558 *p++ = c;
559 }
560}
561
562/* Read a null-terminated string from stdin and add it to the list of
563 arguments to pass to the command.
564 Return -1 if eof (either physical or logical) is reached,
565 otherwise the length of the string read (including the null). */
566
567static int
568read_string ()
569{
570 static boolean eof = false;
571 int len;
572 char *p = linebuf;
573 /* Including the NUL, the args must not grow past this point. */
574 char *endbuf = linebuf + arg_max - initial_argv_chars - 1;
575
576 if (eof)
577 return -1;
578 while (1)
579 {
580 int c = getc (stdin);
581 if (c == EOF)
582 {
583 eof = true;
584 if (p == linebuf)
585 return -1;
586 *p++ = '\0';
587 len = p - linebuf;
588 if (!replace_pat)
589 push_arg (linebuf, len);
590 return len;
591 }
592 if (c == '\0')
593 {
594 lineno++; /* For -l. */
595 *p++ = '\0';
596 len = p - linebuf;
597 if (!replace_pat)
598 push_arg (linebuf, len);
599 return len;
600 }
601 if (p >= endbuf)
602 fatalError ("argument line too long");
603 *p++ = c;
604 }
605}
606
607/* Replace all instances of `replace_pat' in ARG with `linebuf',
608 and add the resulting string to the list of arguments for the command
609 to execute.
610 ARGLEN is the length of ARG, not including the null.
611 LBLEN is the length of `linebuf', not including the null.
612
613 COMPAT: insertions on the SYSV version are limited to 255 chars per line,
614 and a max of 5 occurences of replace_pat in the initial-arguments.
615 Those restrictions do not exist here. */
616
617static void
618do_insert (arg, arglen, lblen)
619 char *arg;
620 size_t arglen;
621 size_t lblen;
622{
623 /* Temporary copy of each arg with the replace pattern replaced by the
624 real arg. */
625 static char *insertbuf;
626 char *p;
627 int bytes_left = arg_max - 1; /* Bytes left on the command line. */
628
629 if (!insertbuf)
630 insertbuf = (char *) xmalloc (arg_max + 1);
631 p = insertbuf;
632
633 do
634 {
635 size_t len; /* Length in ARG before `replace_pat'. */
636 char *s = strstr (arg, replace_pat);
637 if (s)
638 len = s - arg;
639 else
640 len = arglen;
641 bytes_left -= len;
642 if (bytes_left <= 0)
643 break;
644
645 strncpy (p, arg, len);
646 p += len;
647 arg += len;
648 arglen -= len;
649
650 if (s)
651 {
652 bytes_left -= lblen;
653 if (bytes_left <= 0)
654 break;
655 strcpy (p, linebuf);
656 arg += rplen;
657 arglen -= rplen;
658 p += lblen;
659 }
660 }
661 while (*arg);
662 if (*arg)
663 fatalError ("command too long");
664 *p++ = '\0';
665 push_arg (insertbuf, p - insertbuf);
666}
667
668/* Add ARG to the end of the list of arguments `cmd_argv' to pass
669 to the command.
670 LEN is the length of ARG, including the terminating null.
671 If this brings the list up to its maximum size, execute the command. */
672
673static void
674push_arg (arg, len)
675 char *arg;
676 size_t len;
677{
678 if (arg)
679 {
680 if (cmd_argv_chars + len > arg_max)
681 {
682 if (initial_args || cmd_argc == initial_argc)
683 fatalError ("can not fit single argument within argument list size limit");
684 if (replace_pat
685 || (exit_if_size_exceeded &&
686 (lines_per_exec || args_per_exec)))
687 fatalError ("argument list too long");
688 do_exec ();
689 }
690 if (!initial_args && args_per_exec &&
691 cmd_argc - initial_argc == args_per_exec)
692 do_exec ();
693 }
694
695 if (cmd_argc >= cmd_argv_alloc)
696 {
697 if (!cmd_argv)
698 {
699 cmd_argv_alloc = 64;
700 cmd_argv = (char **) xmalloc (sizeof (char *) * cmd_argv_alloc);
701 }
702 else
703 {
704 cmd_argv_alloc *= 2;
705 cmd_argv = (char **) xrealloc (cmd_argv,
706 sizeof (char *) * cmd_argv_alloc);
707 }
708 }
709
710 if (!arg)
711 cmd_argv[cmd_argc++] = NULL;
712 else
713 {
714 cmd_argv[cmd_argc++] = argbuf + cmd_argv_chars;
715 strcpy (argbuf + cmd_argv_chars, arg);
716 cmd_argv_chars += len;
717 }
718}
719
720/* Print the arguments of the command to execute.
721 If ASK is nonzero, prompt the user for a response, and
722 if the user responds affirmatively, return true;
723 otherwise, return false. */
724
725static boolean
726print_args (ask)
727 boolean ask;
728{
729 int i;
730
731 for (i = 0; i < cmd_argc - 1; i++)
732 fprintf (stderr, "%s ", cmd_argv[i]);
733 if (ask)
734 {
735 static FILE *tty_stream;
736 int c, savec;
737
738 if (!tty_stream)
739 {
740 tty_stream = fopen ("/dev/tty", "r");
741 if (!tty_stream)
742 fatalError (" Could not open /dev/tty");
743 }
744 fputs ("?...", stderr);
745 fflush (stderr);
746 c = savec = getc (tty_stream);
747 while (c != EOF && c != '\n')
748 c = getc (tty_stream);
749 if (savec == 'y' || savec == 'Y')
750 return true;
751 }
752 else
753 putc ('\n', stderr);
754
755 return false;
756}
757
758/* Execute the command that has been built in `cmd_argv'. This may involve
759 waiting for processes that were previously executed. */
760
761static void
762do_exec ()
763{
764 pid_t child;
765
766 push_arg ((char *) NULL, 0); /* Null terminate the arg list. */
767 if (!query_before_executing || print_args (true))
768 {
769 if (proc_max && procs_executing >= proc_max)
770 wait_for_proc (false);
771 if (!query_before_executing && print_command)
772 print_args (false);
773 /* If we run out of processes, wait for a child to return and
774 try again. */
775 while ((child = fork ()) < 0 && errno == EAGAIN && procs_executing)
776 wait_for_proc (false);
777 switch (child)
778 {
779 case -1:
780 fatalError ("cannot fork");
781
782 case 0: /* Child. */
783 execvp (cmd_argv[0], cmd_argv);
784 errorMsg ("failed to exec '%s'", cmd_argv[0]);
785 _exit (errno == ENOENT ? 127 : 126);
786 }
787 add_proc (child);
788 }
789
790 cmd_argc = initial_argc;
791 cmd_argv_chars = initial_argv_chars;
792}
793
794/* Add the process with id PID to the list of processes that have
795 been executed. */
796
797static void
798add_proc (pid)
799 pid_t pid;
800{
801 int i;
802
803 /* Find an empty slot. */
804 for (i = 0; i < pids_alloc && pids[i]; i++)
805 ;
806 if (i == pids_alloc)
807 {
808 if (pids_alloc == 0)
809 {
810 pids_alloc = proc_max ? proc_max : 64;
811 pids = (pid_t *) xmalloc (sizeof (pid_t) * pids_alloc);
812 }
813 else
814 {
815 pids_alloc *= 2;
816 pids = (pid_t *) xrealloc (pids,
817 sizeof (pid_t) * pids_alloc);
818 }
819 memset (&pids[i], '\0', sizeof (pid_t) * (pids_alloc - i));
820 }
821 pids[i] = pid;
822 procs_executing++;
823 procs_executed++;
824}
825
826/* If ALL is true, wait for all child processes to finish;
827 otherwise, wait for one child process to finish.
828 Remove the processes that finish from the list of executing processes. */
829
830static void
831wait_for_proc (all)
832 boolean all;
833{
834 while (procs_executing)
835 {
836 int i, status;
837
838 do
839 {
840 pid_t pid;
841
842 pid = wait (&status);
843 if (pid < 0)
844 fatalError ("error waiting for child process");
845
846 /* Find the entry in `pids' for the child process
847 that exited. */
848 for (i = 0; i < pids_alloc && pid != pids[i]; i++)
849 ;
850 }
851 while (i == pids_alloc); /* A child died that we didn't start? */
852
853 /* Remove the child from the list. */
854 pids[i] = 0;
855 procs_executing--;
856
857 if (WEXITSTATUS (status) == 126 || WEXITSTATUS (status) == 127)
858 exit (WEXITSTATUS (status)); /* Can't find or run the command. */
859 if (WEXITSTATUS (status) == 255)
860 fatalError ( "%s: exited with status 255; aborting", cmd_argv[0]);
861 if (WIFSTOPPED (status))
862 fatalError ( "%s: stopped by signal %d", cmd_argv[0], WSTOPSIG (status));
863 if (WIFSIGNALED (status))
864 fatalError ("%s: terminated by signal %d", cmd_argv[0], WTERMSIG (status));
865 if (WEXITSTATUS (status) != 0)
866 child_error = 123;
867
868 if (!all)
869 break;
870 }
871}
872
873/* Return the value of the number represented in STR.
874 OPTION is the command line option to which STR is the argument.
875 If the value does not fall within the boundaries MIN and MAX,
876 Print an error message mentioning OPTION and exit. */
877
878static long
879parse_num (str, option, min, max)
880 char *str;
881 int option;
882 long min;
883 long max;
884{
885 char *eptr;
886 long val;
887
888 val = strtol (str, &eptr, 10);
889 if (eptr == str || *eptr)
890 {
891 fprintf (stderr, "%s: invalid number for -%c option\n",
892 program_name, option);
893 usage (xargs_usage);
894 }
895 else if (val < min)
896 {
897 fprintf (stderr, "%s: value for -%c option must be >= %ld\n",
898 program_name, option, min);
899 usage (xargs_usage);
900 }
901 else if (max >= 0 && val > max)
902 {
903 fprintf (stderr, "%s: value for -%c option must be < %ld\n",
904 program_name, option, max);
905 usage (xargs_usage);
906 }
907 return val;
908}
909
910/* Return how much of ARG_MAX is used by the environment. */
911
912static long
913env_size (envp)
914 char **envp;
915{
916 long len = 0;
917
918 while (*envp)
919 len += strlen (*envp++) + 1;
920
921 return len;
922}
923