xref: /aosp_15_r20/external/toybox/toys/posix/xargs.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* xargs.c - Run command with arguments taken from stdin.
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2011 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  *
5*cf5a6c84SAndroid Build Coastguard Worker  * See http://opengroup.org/onlinepubs/9699919799/utilities/xargs.html
6*cf5a6c84SAndroid Build Coastguard Worker  *
7*cf5a6c84SAndroid Build Coastguard Worker  * TODO: Rich's whitespace objection, env size isn't fixed anymore.
8*cf5a6c84SAndroid Build Coastguard Worker  * TODO: -I	Insert mode
9*cf5a6c84SAndroid Build Coastguard Worker  * TODO: -L	Max number of lines of input per command
10*cf5a6c84SAndroid Build Coastguard Worker  * TODO: -x	Exit if can't fit everything in one command
11*cf5a6c84SAndroid Build Coastguard Worker 
12*cf5a6c84SAndroid Build Coastguard Worker USE_XARGS(NEWTOY(xargs, "^E:P#<0(null)=1optr(no-run-if-empty)n#<1(max-args)s#0[!0E]", TOYFLAG_USR|TOYFLAG_BIN))
13*cf5a6c84SAndroid Build Coastguard Worker 
14*cf5a6c84SAndroid Build Coastguard Worker config XARGS
15*cf5a6c84SAndroid Build Coastguard Worker   bool "xargs"
16*cf5a6c84SAndroid Build Coastguard Worker   default y
17*cf5a6c84SAndroid Build Coastguard Worker   help
18*cf5a6c84SAndroid Build Coastguard Worker     usage: xargs [-0Pprt] [-snE STR] COMMAND...
19*cf5a6c84SAndroid Build Coastguard Worker 
20*cf5a6c84SAndroid Build Coastguard Worker     Run command line one or more times, appending arguments from stdin.
21*cf5a6c84SAndroid Build Coastguard Worker 
22*cf5a6c84SAndroid Build Coastguard Worker     If COMMAND exits with 255, don't launch another even if arguments remain.
23*cf5a6c84SAndroid Build Coastguard Worker 
24*cf5a6c84SAndroid Build Coastguard Worker     -0	Each argument is NULL terminated, no whitespace or quote processing
25*cf5a6c84SAndroid Build Coastguard Worker     -E	Stop at line matching string
26*cf5a6c84SAndroid Build Coastguard Worker     -n	Max number of arguments per command
27*cf5a6c84SAndroid Build Coastguard Worker     -o	Open tty for COMMAND's stdin (default /dev/null)
28*cf5a6c84SAndroid Build Coastguard Worker     -P	Parallel processes (default 1)
29*cf5a6c84SAndroid Build Coastguard Worker     -p	Prompt for y/n from tty before running each command
30*cf5a6c84SAndroid Build Coastguard Worker     -r	Don't run with empty input (otherwise always run command once)
31*cf5a6c84SAndroid Build Coastguard Worker     -s	Size in bytes per command line
32*cf5a6c84SAndroid Build Coastguard Worker     -t	Trace, print command line to stderr
33*cf5a6c84SAndroid Build Coastguard Worker */
34*cf5a6c84SAndroid Build Coastguard Worker 
35*cf5a6c84SAndroid Build Coastguard Worker #define FOR_xargs
36*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
37*cf5a6c84SAndroid Build Coastguard Worker 
GLOBALS(long s,n,P;char * E;long entries,bytes,np;char delim;FILE * tty;)38*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
39*cf5a6c84SAndroid Build Coastguard Worker   long s, n, P;
40*cf5a6c84SAndroid Build Coastguard Worker   char *E;
41*cf5a6c84SAndroid Build Coastguard Worker 
42*cf5a6c84SAndroid Build Coastguard Worker   long entries, bytes, np;
43*cf5a6c84SAndroid Build Coastguard Worker   char delim;
44*cf5a6c84SAndroid Build Coastguard Worker   FILE *tty;
45*cf5a6c84SAndroid Build Coastguard Worker )
46*cf5a6c84SAndroid Build Coastguard Worker 
47*cf5a6c84SAndroid Build Coastguard Worker // If !entry count TT.bytes and TT.entries, stopping at max.
48*cf5a6c84SAndroid Build Coastguard Worker // Otherwise, fill out entry[].
49*cf5a6c84SAndroid Build Coastguard Worker 
50*cf5a6c84SAndroid Build Coastguard Worker // Returning NULL means need more data.
51*cf5a6c84SAndroid Build Coastguard Worker // Returning char * means hit data limits, start of data left over
52*cf5a6c84SAndroid Build Coastguard Worker // Returning 1 means hit data limits, but consumed all data
53*cf5a6c84SAndroid Build Coastguard Worker // Returning 2 means hit -E STR
54*cf5a6c84SAndroid Build Coastguard Worker 
55*cf5a6c84SAndroid Build Coastguard Worker static char *handle_entries(char *data, char **entry)
56*cf5a6c84SAndroid Build Coastguard Worker {
57*cf5a6c84SAndroid Build Coastguard Worker   if (TT.delim) {
58*cf5a6c84SAndroid Build Coastguard Worker     char *save, *ss, *s;
59*cf5a6c84SAndroid Build Coastguard Worker 
60*cf5a6c84SAndroid Build Coastguard Worker     // Chop up whitespace delimited string into args
61*cf5a6c84SAndroid Build Coastguard Worker     for (s = data; *s; TT.entries++) {
62*cf5a6c84SAndroid Build Coastguard Worker       while (isspace(*s)) s++;
63*cf5a6c84SAndroid Build Coastguard Worker       if (TT.n && TT.entries >= TT.n) return *s ? s : (char *)1;
64*cf5a6c84SAndroid Build Coastguard Worker       if (!*s) break;
65*cf5a6c84SAndroid Build Coastguard Worker       save = ss = s;
66*cf5a6c84SAndroid Build Coastguard Worker 
67*cf5a6c84SAndroid Build Coastguard Worker       // Specifying -s can cause "argument too long" errors.
68*cf5a6c84SAndroid Build Coastguard Worker       if (!FLAG(s)) TT.bytes += sizeof(void *)+1;
69*cf5a6c84SAndroid Build Coastguard Worker       for (;;) {
70*cf5a6c84SAndroid Build Coastguard Worker         if (++TT.bytes >= TT.s) return save;
71*cf5a6c84SAndroid Build Coastguard Worker         if (!*s || isspace(*s)) break;
72*cf5a6c84SAndroid Build Coastguard Worker         s++;
73*cf5a6c84SAndroid Build Coastguard Worker       }
74*cf5a6c84SAndroid Build Coastguard Worker       if (TT.E && strstart(&ss, TT.E) && ss == s) return (char *)2;
75*cf5a6c84SAndroid Build Coastguard Worker       if (entry) {
76*cf5a6c84SAndroid Build Coastguard Worker         entry[TT.entries] = save;
77*cf5a6c84SAndroid Build Coastguard Worker         if (*s) *s++ = 0;
78*cf5a6c84SAndroid Build Coastguard Worker       }
79*cf5a6c84SAndroid Build Coastguard Worker     }
80*cf5a6c84SAndroid Build Coastguard Worker 
81*cf5a6c84SAndroid Build Coastguard Worker   // -0 support
82*cf5a6c84SAndroid Build Coastguard Worker   } else {
83*cf5a6c84SAndroid Build Coastguard Worker     long bytes = TT.bytes+sizeof(char *)+strlen(data)+1;
84*cf5a6c84SAndroid Build Coastguard Worker 
85*cf5a6c84SAndroid Build Coastguard Worker     if (bytes >= TT.s || (TT.n && TT.entries >= TT.n)) return data;
86*cf5a6c84SAndroid Build Coastguard Worker     TT.bytes = bytes;
87*cf5a6c84SAndroid Build Coastguard Worker     if (entry) entry[TT.entries] = data;
88*cf5a6c84SAndroid Build Coastguard Worker     TT.entries++;
89*cf5a6c84SAndroid Build Coastguard Worker   }
90*cf5a6c84SAndroid Build Coastguard Worker 
91*cf5a6c84SAndroid Build Coastguard Worker   return 0;
92*cf5a6c84SAndroid Build Coastguard Worker }
93*cf5a6c84SAndroid Build Coastguard Worker 
94*cf5a6c84SAndroid Build Coastguard Worker // Handle SIGUSR1 and SIGUSR2 for -P
signal_P(int sig)95*cf5a6c84SAndroid Build Coastguard Worker static void signal_P(int sig)
96*cf5a6c84SAndroid Build Coastguard Worker {
97*cf5a6c84SAndroid Build Coastguard Worker   if (sig == SIGUSR2 && TT.P>1) TT.P--;
98*cf5a6c84SAndroid Build Coastguard Worker   else TT.P++;
99*cf5a6c84SAndroid Build Coastguard Worker }
100*cf5a6c84SAndroid Build Coastguard Worker 
waitchild(int options)101*cf5a6c84SAndroid Build Coastguard Worker static void waitchild(int options)
102*cf5a6c84SAndroid Build Coastguard Worker {
103*cf5a6c84SAndroid Build Coastguard Worker   int ii, status;
104*cf5a6c84SAndroid Build Coastguard Worker 
105*cf5a6c84SAndroid Build Coastguard Worker   if (1>waitpid(-1, &status, options)) return;
106*cf5a6c84SAndroid Build Coastguard Worker   TT.np--;
107*cf5a6c84SAndroid Build Coastguard Worker   ii = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)+128;
108*cf5a6c84SAndroid Build Coastguard Worker   if (ii == 255) {
109*cf5a6c84SAndroid Build Coastguard Worker     error_msg("%s: exited with status 255; aborting", *toys.optargs);
110*cf5a6c84SAndroid Build Coastguard Worker     toys.exitval = 124;
111*cf5a6c84SAndroid Build Coastguard Worker   } else if ((ii|1)==127) toys.exitval = ii;
112*cf5a6c84SAndroid Build Coastguard Worker   else if (ii>127) toys.exitval = 125;
113*cf5a6c84SAndroid Build Coastguard Worker   else if (ii) toys.exitval = 123;
114*cf5a6c84SAndroid Build Coastguard Worker }
115*cf5a6c84SAndroid Build Coastguard Worker 
xargs_main(void)116*cf5a6c84SAndroid Build Coastguard Worker void xargs_main(void)
117*cf5a6c84SAndroid Build Coastguard Worker {
118*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *dlist = 0, *dtemp;
119*cf5a6c84SAndroid Build Coastguard Worker   int entries, bytes, done = 0;
120*cf5a6c84SAndroid Build Coastguard Worker   char *data = 0, **out = 0;
121*cf5a6c84SAndroid Build Coastguard Worker   pid_t pid = 0;
122*cf5a6c84SAndroid Build Coastguard Worker 
123*cf5a6c84SAndroid Build Coastguard Worker   xsignal_flags(SIGUSR1, signal_P, SA_RESTART);
124*cf5a6c84SAndroid Build Coastguard Worker   xsignal_flags(SIGUSR2, signal_P, SA_RESTART);
125*cf5a6c84SAndroid Build Coastguard Worker 
126*cf5a6c84SAndroid Build Coastguard Worker   // POSIX requires that we never hit the ARG_MAX limit, even if we try to
127*cf5a6c84SAndroid Build Coastguard Worker   // with -s. POSIX also says we have to reserve 2048 bytes "to guarantee
128*cf5a6c84SAndroid Build Coastguard Worker   // that the invoked utility has room to modify its environment variables
129*cf5a6c84SAndroid Build Coastguard Worker   // and command line arguments and still be able to invoke another utility",
130*cf5a6c84SAndroid Build Coastguard Worker   // though obviously that's not really something you can guarantee.
131*cf5a6c84SAndroid Build Coastguard Worker   if (!FLAG(s)) TT.s = sysconf(_SC_ARG_MAX) - environ_bytes() - 4096;
132*cf5a6c84SAndroid Build Coastguard Worker 
133*cf5a6c84SAndroid Build Coastguard Worker   TT.delim = '\n'*!FLAG(0);
134*cf5a6c84SAndroid Build Coastguard Worker 
135*cf5a6c84SAndroid Build Coastguard Worker   // If no optargs, call echo.
136*cf5a6c84SAndroid Build Coastguard Worker   if (!toys.optc) {
137*cf5a6c84SAndroid Build Coastguard Worker     free(toys.optargs);
138*cf5a6c84SAndroid Build Coastguard Worker     *(toys.optargs = xzalloc(2*sizeof(char *)))="echo";
139*cf5a6c84SAndroid Build Coastguard Worker     toys.optc = 1;
140*cf5a6c84SAndroid Build Coastguard Worker   }
141*cf5a6c84SAndroid Build Coastguard Worker 
142*cf5a6c84SAndroid Build Coastguard Worker   // count entries
143*cf5a6c84SAndroid Build Coastguard Worker   for (entries = 0, bytes = -1; entries < toys.optc; entries++)
144*cf5a6c84SAndroid Build Coastguard Worker     bytes += strlen(toys.optargs[entries])+1+sizeof(char *)*!FLAG(s);
145*cf5a6c84SAndroid Build Coastguard Worker   if (bytes >= TT.s) error_exit("command too long");
146*cf5a6c84SAndroid Build Coastguard Worker 
147*cf5a6c84SAndroid Build Coastguard Worker   // Loop through exec chunks.
148*cf5a6c84SAndroid Build Coastguard Worker   while (data || !done) {
149*cf5a6c84SAndroid Build Coastguard Worker     TT.entries = 0;
150*cf5a6c84SAndroid Build Coastguard Worker     TT.bytes = bytes;
151*cf5a6c84SAndroid Build Coastguard Worker     if (TT.np) waitchild(WNOHANG*!(TT.np==TT.P||(!data && done)));
152*cf5a6c84SAndroid Build Coastguard Worker     if (toys.exitval==124) break;
153*cf5a6c84SAndroid Build Coastguard Worker 
154*cf5a6c84SAndroid Build Coastguard Worker     // Arbitrary number of execs, can't just leak memory each time...
155*cf5a6c84SAndroid Build Coastguard Worker     llist_traverse(dlist, llist_free_double);
156*cf5a6c84SAndroid Build Coastguard Worker     dlist = 0;
157*cf5a6c84SAndroid Build Coastguard Worker     free(out);
158*cf5a6c84SAndroid Build Coastguard Worker     out = 0;
159*cf5a6c84SAndroid Build Coastguard Worker 
160*cf5a6c84SAndroid Build Coastguard Worker     // Loop reading input
161*cf5a6c84SAndroid Build Coastguard Worker     for (;;) {
162*cf5a6c84SAndroid Build Coastguard Worker       // Read line
163*cf5a6c84SAndroid Build Coastguard Worker       if (!data) {
164*cf5a6c84SAndroid Build Coastguard Worker         size_t l = 0;
165*cf5a6c84SAndroid Build Coastguard Worker 
166*cf5a6c84SAndroid Build Coastguard Worker         if (getdelim(&data, &l, TT.delim, stdin)<0) {
167*cf5a6c84SAndroid Build Coastguard Worker           data = 0;
168*cf5a6c84SAndroid Build Coastguard Worker           done++;
169*cf5a6c84SAndroid Build Coastguard Worker           break;
170*cf5a6c84SAndroid Build Coastguard Worker         }
171*cf5a6c84SAndroid Build Coastguard Worker       }
172*cf5a6c84SAndroid Build Coastguard Worker       dlist_add(&dlist, data);
173*cf5a6c84SAndroid Build Coastguard Worker       // Count data used
174*cf5a6c84SAndroid Build Coastguard Worker       if (!(data = handle_entries(data, 0))) continue;
175*cf5a6c84SAndroid Build Coastguard Worker       if (data == (char *)2) done++;
176*cf5a6c84SAndroid Build Coastguard Worker       if ((unsigned long)data <= 2) data = 0;
177*cf5a6c84SAndroid Build Coastguard Worker       else data = xstrdup(data);
178*cf5a6c84SAndroid Build Coastguard Worker 
179*cf5a6c84SAndroid Build Coastguard Worker       break;
180*cf5a6c84SAndroid Build Coastguard Worker     }
181*cf5a6c84SAndroid Build Coastguard Worker 
182*cf5a6c84SAndroid Build Coastguard Worker     if (!TT.entries) {
183*cf5a6c84SAndroid Build Coastguard Worker       if (data) error_exit("argument too long");
184*cf5a6c84SAndroid Build Coastguard Worker       if (pid || FLAG(r)) break;
185*cf5a6c84SAndroid Build Coastguard Worker     }
186*cf5a6c84SAndroid Build Coastguard Worker 
187*cf5a6c84SAndroid Build Coastguard Worker     // Fill out command line to exec
188*cf5a6c84SAndroid Build Coastguard Worker     out = xzalloc((toys.optc+TT.entries+1)*sizeof(char *));
189*cf5a6c84SAndroid Build Coastguard Worker     memcpy(out, toys.optargs, toys.optc*sizeof(char *));
190*cf5a6c84SAndroid Build Coastguard Worker     TT.entries = 0;
191*cf5a6c84SAndroid Build Coastguard Worker     TT.bytes = bytes;
192*cf5a6c84SAndroid Build Coastguard Worker     dlist_terminate(dlist);
193*cf5a6c84SAndroid Build Coastguard Worker     for (dtemp = dlist; dtemp; dtemp = dtemp->next)
194*cf5a6c84SAndroid Build Coastguard Worker       handle_entries(dtemp->data, out+entries);
195*cf5a6c84SAndroid Build Coastguard Worker 
196*cf5a6c84SAndroid Build Coastguard Worker     if (FLAG(p) || FLAG(t)) {
197*cf5a6c84SAndroid Build Coastguard Worker       int i;
198*cf5a6c84SAndroid Build Coastguard Worker 
199*cf5a6c84SAndroid Build Coastguard Worker       for (i = 0; out[i]; ++i) fprintf(stderr, "%s ", out[i]);
200*cf5a6c84SAndroid Build Coastguard Worker       if (FLAG(p)) {
201*cf5a6c84SAndroid Build Coastguard Worker         fprintf(stderr, "?");
202*cf5a6c84SAndroid Build Coastguard Worker         if (!TT.tty) TT.tty = xfopen("/dev/tty", "re");
203*cf5a6c84SAndroid Build Coastguard Worker         if (!fyesno(TT.tty, 0)) continue;
204*cf5a6c84SAndroid Build Coastguard Worker       } else fprintf(stderr, "\n");
205*cf5a6c84SAndroid Build Coastguard Worker     }
206*cf5a6c84SAndroid Build Coastguard Worker 
207*cf5a6c84SAndroid Build Coastguard Worker     if (!(pid = XVFORK())) {
208*cf5a6c84SAndroid Build Coastguard Worker       close(0);
209*cf5a6c84SAndroid Build Coastguard Worker       xopen_stdio(FLAG(o) ? "/dev/tty" : "/dev/null", O_RDONLY|O_CLOEXEC);
210*cf5a6c84SAndroid Build Coastguard Worker       xexec(out);
211*cf5a6c84SAndroid Build Coastguard Worker     }
212*cf5a6c84SAndroid Build Coastguard Worker     TT.np++;
213*cf5a6c84SAndroid Build Coastguard Worker   }
214*cf5a6c84SAndroid Build Coastguard Worker   while (TT.np) waitchild(0);
215*cf5a6c84SAndroid Build Coastguard Worker   if (TT.tty) fclose(TT.tty);
216*cf5a6c84SAndroid Build Coastguard Worker }
217