xargs.c revision 1.12 1 1.12 kleink /* $NetBSD: xargs.c,v 1.12 1999/12/22 14:41:01 kleink Exp $ */
2 1.7 jtc
3 1.1 cgd /*-
4 1.7 jtc * Copyright (c) 1990, 1993
5 1.7 jtc * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * This code is derived from software contributed to Berkeley by
8 1.1 cgd * John B. Roll Jr.
9 1.1 cgd *
10 1.1 cgd * Redistribution and use in source and binary forms, with or without
11 1.1 cgd * modification, are permitted provided that the following conditions
12 1.1 cgd * are met:
13 1.1 cgd * 1. Redistributions of source code must retain the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer.
15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 cgd * notice, this list of conditions and the following disclaimer in the
17 1.1 cgd * documentation and/or other materials provided with the distribution.
18 1.1 cgd * 3. All advertising materials mentioning features or use of this software
19 1.1 cgd * must display the following acknowledgement:
20 1.1 cgd * This product includes software developed by the University of
21 1.1 cgd * California, Berkeley and its contributors.
22 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
23 1.1 cgd * may be used to endorse or promote products derived from this software
24 1.1 cgd * without specific prior written permission.
25 1.1 cgd *
26 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 1.1 cgd * SUCH DAMAGE.
37 1.1 cgd */
38 1.1 cgd
39 1.9 lukem #include <sys/cdefs.h>
40 1.1 cgd #ifndef lint
41 1.9 lukem __COPYRIGHT("@(#) Copyright (c) 1990, 1993\n\
42 1.9 lukem The Regents of the University of California. All rights reserved.\n");
43 1.1 cgd #endif /* not lint */
44 1.1 cgd
45 1.1 cgd #ifndef lint
46 1.7 jtc #if 0
47 1.7 jtc static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93";
48 1.7 jtc #endif
49 1.12 kleink __RCSID("$NetBSD: xargs.c,v 1.12 1999/12/22 14:41:01 kleink Exp $");
50 1.1 cgd #endif /* not lint */
51 1.1 cgd
52 1.1 cgd #include <sys/types.h>
53 1.1 cgd #include <sys/wait.h>
54 1.12 kleink #include <err.h>
55 1.1 cgd #include <errno.h>
56 1.12 kleink #include <langinfo.h>
57 1.12 kleink #include <limits.h>
58 1.12 kleink #include <locale.h>
59 1.12 kleink #include <paths.h>
60 1.12 kleink #include <regex.h>
61 1.12 kleink #include <signal.h>
62 1.1 cgd #include <stdio.h>
63 1.1 cgd #include <stdlib.h>
64 1.1 cgd #include <string.h>
65 1.1 cgd #include <unistd.h>
66 1.1 cgd #include "pathnames.h"
67 1.1 cgd
68 1.12 kleink static int pflag, tflag, zflag, rval;
69 1.12 kleink static FILE *promptfile;
70 1.12 kleink static regex_t yesexpr;
71 1.12 kleink
72 1.12 kleink static void run __P((char **));
73 1.12 kleink int main __P((int, char **));
74 1.12 kleink static void usage __P((void));
75 1.1 cgd
76 1.5 jtc int
77 1.1 cgd main(argc, argv)
78 1.1 cgd int argc;
79 1.1 cgd char **argv;
80 1.1 cgd {
81 1.9 lukem int ch;
82 1.9 lukem char *p, *bbp, *ebp, **bxp, **exp, **xp;
83 1.1 cgd int cnt, indouble, insingle, nargs, nflag, nline, xflag;
84 1.1 cgd char **av, *argp;
85 1.6 jtc
86 1.6 jtc setlocale(LC_ALL, "");
87 1.1 cgd
88 1.1 cgd /*
89 1.1 cgd * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
90 1.1 cgd * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given
91 1.1 cgd * that the smallest argument is 2 bytes in length, this means that
92 1.1 cgd * the number of arguments is limited to:
93 1.1 cgd *
94 1.1 cgd * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
95 1.1 cgd *
96 1.1 cgd * We arbitrarily limit the number of arguments to 5000. This is
97 1.1 cgd * allowed by POSIX.2 as long as the resulting minimum exec line is
98 1.1 cgd * at least LINE_MAX. Realloc'ing as necessary is possible, but
99 1.1 cgd * probably not worthwhile.
100 1.1 cgd */
101 1.1 cgd nargs = 5000;
102 1.1 cgd nline = ARG_MAX - 4 * 1024;
103 1.1 cgd nflag = xflag = 0;
104 1.12 kleink while ((ch = getopt(argc, argv, "0n:ps:tx")) != -1)
105 1.1 cgd switch(ch) {
106 1.8 lukem case '0':
107 1.8 lukem zflag = 1;
108 1.8 lukem break;
109 1.1 cgd case 'n':
110 1.1 cgd nflag = 1;
111 1.1 cgd if ((nargs = atoi(optarg)) <= 0)
112 1.7 jtc errx(1, "illegal argument count");
113 1.1 cgd break;
114 1.12 kleink case 'p':
115 1.12 kleink pflag = tflag = 1;
116 1.12 kleink break;
117 1.1 cgd case 's':
118 1.1 cgd nline = atoi(optarg);
119 1.1 cgd break;
120 1.1 cgd case 't':
121 1.1 cgd tflag = 1;
122 1.1 cgd break;
123 1.1 cgd case 'x':
124 1.1 cgd xflag = 1;
125 1.1 cgd break;
126 1.1 cgd case '?':
127 1.1 cgd default:
128 1.1 cgd usage();
129 1.1 cgd }
130 1.1 cgd argc -= optind;
131 1.1 cgd argv += optind;
132 1.1 cgd
133 1.1 cgd if (xflag && !nflag)
134 1.1 cgd usage();
135 1.1 cgd
136 1.1 cgd /*
137 1.1 cgd * Allocate pointers for the utility name, the utility arguments,
138 1.1 cgd * the maximum arguments to be read from stdin and the trailing
139 1.1 cgd * NULL.
140 1.1 cgd */
141 1.1 cgd if (!(av = bxp =
142 1.1 cgd malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **))))
143 1.9 lukem err(1, "malloc");
144 1.1 cgd
145 1.1 cgd /*
146 1.1 cgd * Use the user's name for the utility as argv[0], just like the
147 1.1 cgd * shell. Echo is the default. Set up pointers for the user's
148 1.1 cgd * arguments.
149 1.1 cgd */
150 1.1 cgd if (!*argv)
151 1.1 cgd cnt = strlen(*bxp++ = _PATH_ECHO);
152 1.1 cgd else {
153 1.1 cgd cnt = 0;
154 1.1 cgd do {
155 1.1 cgd cnt += strlen(*bxp++ = *argv) + 1;
156 1.1 cgd } while (*++argv);
157 1.1 cgd }
158 1.1 cgd
159 1.1 cgd /*
160 1.1 cgd * Set up begin/end/traversing pointers into the array. The -n
161 1.1 cgd * count doesn't include the trailing NULL pointer, so the malloc
162 1.1 cgd * added in an extra slot.
163 1.1 cgd */
164 1.1 cgd exp = (xp = bxp) + nargs;
165 1.1 cgd
166 1.1 cgd /*
167 1.1 cgd * Allocate buffer space for the arguments read from stdin and the
168 1.1 cgd * trailing NULL. Buffer space is defined as the default or specified
169 1.1 cgd * space, minus the length of the utility name and arguments. Set up
170 1.1 cgd * begin/end/traversing pointers into the array. The -s count does
171 1.1 cgd * include the trailing NULL, so the malloc didn't add in an extra
172 1.1 cgd * slot.
173 1.1 cgd */
174 1.1 cgd nline -= cnt;
175 1.1 cgd if (nline <= 0)
176 1.7 jtc errx(1, "insufficient space for command");
177 1.1 cgd
178 1.1 cgd if (!(bbp = malloc((u_int)nline + 1)))
179 1.9 lukem err(1, "malloc");
180 1.1 cgd ebp = (argp = p = bbp) + nline - 1;
181 1.1 cgd
182 1.12 kleink if (pflag) {
183 1.12 kleink int error;
184 1.12 kleink
185 1.12 kleink if ((promptfile = fopen(_PATH_TTY, "r")) == NULL)
186 1.12 kleink err(1, "prompt mode: cannot open input");
187 1.12 kleink if ((error = regcomp(&yesexpr, nl_langinfo(YESEXPR), REG_NOSUB))
188 1.12 kleink != 0) {
189 1.12 kleink char msg[NL_TEXTMAX];
190 1.12 kleink
191 1.12 kleink (void)regerror(error, NULL, msg, sizeof (msg));
192 1.12 kleink err(1, "cannot compile yesexpr: %s", msg);
193 1.12 kleink }
194 1.12 kleink }
195 1.12 kleink
196 1.1 cgd for (insingle = indouble = 0;;)
197 1.1 cgd switch(ch = getchar()) {
198 1.1 cgd case EOF:
199 1.1 cgd /* No arguments since last exec. */
200 1.1 cgd if (p == bbp)
201 1.7 jtc exit(rval);
202 1.1 cgd
203 1.1 cgd /* Nothing since end of last argument. */
204 1.1 cgd if (argp == p) {
205 1.1 cgd *xp = NULL;
206 1.1 cgd run(av);
207 1.7 jtc exit(rval);
208 1.1 cgd }
209 1.1 cgd goto arg1;
210 1.1 cgd case ' ':
211 1.1 cgd case '\t':
212 1.1 cgd /* Quotes escape tabs and spaces. */
213 1.8 lukem if (insingle || indouble || zflag)
214 1.1 cgd goto addch;
215 1.1 cgd goto arg2;
216 1.8 lukem case '\0':
217 1.8 lukem if (zflag)
218 1.8 lukem goto arg2;
219 1.8 lukem goto addch;
220 1.1 cgd case '\n':
221 1.8 lukem if (zflag)
222 1.8 lukem goto addch;
223 1.1 cgd /* Empty lines are skipped. */
224 1.1 cgd if (argp == p)
225 1.1 cgd continue;
226 1.1 cgd
227 1.1 cgd /* Quotes do not escape newlines. */
228 1.1 cgd arg1: if (insingle || indouble)
229 1.7 jtc errx(1, "unterminated quote");
230 1.1 cgd
231 1.1 cgd arg2: *p = '\0';
232 1.1 cgd *xp++ = argp;
233 1.1 cgd
234 1.1 cgd /*
235 1.1 cgd * If max'd out on args or buffer, or reached EOF,
236 1.1 cgd * run the command. If xflag and max'd out on buffer
237 1.1 cgd * but not on args, object.
238 1.1 cgd */
239 1.1 cgd if (xp == exp || p == ebp || ch == EOF) {
240 1.1 cgd if (xflag && xp != exp && p == ebp)
241 1.7 jtc errx(1, "insufficient space for arguments");
242 1.1 cgd *xp = NULL;
243 1.1 cgd run(av);
244 1.1 cgd if (ch == EOF)
245 1.7 jtc exit(rval);
246 1.1 cgd p = bbp;
247 1.1 cgd xp = bxp;
248 1.1 cgd } else
249 1.1 cgd ++p;
250 1.1 cgd argp = p;
251 1.1 cgd break;
252 1.1 cgd case '\'':
253 1.8 lukem if (indouble || zflag)
254 1.1 cgd goto addch;
255 1.1 cgd insingle = !insingle;
256 1.1 cgd break;
257 1.1 cgd case '"':
258 1.8 lukem if (insingle || zflag)
259 1.1 cgd goto addch;
260 1.1 cgd indouble = !indouble;
261 1.1 cgd break;
262 1.1 cgd case '\\':
263 1.8 lukem if (zflag)
264 1.8 lukem goto addch;
265 1.1 cgd /* Backslash escapes anything, is escaped by quotes. */
266 1.1 cgd if (!insingle && !indouble && (ch = getchar()) == EOF)
267 1.7 jtc errx(1, "backslash at EOF");
268 1.1 cgd /* FALLTHROUGH */
269 1.1 cgd default:
270 1.1 cgd addch: if (p < ebp) {
271 1.1 cgd *p++ = ch;
272 1.1 cgd break;
273 1.1 cgd }
274 1.1 cgd
275 1.1 cgd /* If only one argument, not enough buffer space. */
276 1.1 cgd if (bxp == xp)
277 1.7 jtc errx(1, "insufficient space for argument");
278 1.1 cgd /* Didn't hit argument limit, so if xflag object. */
279 1.1 cgd if (xflag)
280 1.7 jtc errx(1, "insufficient space for arguments");
281 1.1 cgd
282 1.1 cgd *xp = NULL;
283 1.1 cgd run(av);
284 1.1 cgd xp = bxp;
285 1.1 cgd cnt = ebp - argp;
286 1.9 lukem memmove(bbp, argp, cnt);
287 1.1 cgd p = (argp = bbp) + cnt;
288 1.1 cgd *p++ = ch;
289 1.1 cgd break;
290 1.1 cgd }
291 1.1 cgd /* NOTREACHED */
292 1.1 cgd }
293 1.1 cgd
294 1.12 kleink static void
295 1.1 cgd run(argv)
296 1.1 cgd char **argv;
297 1.1 cgd {
298 1.7 jtc volatile int noinvoke;
299 1.9 lukem char **p;
300 1.1 cgd pid_t pid;
301 1.1 cgd int status;
302 1.1 cgd
303 1.1 cgd if (tflag) {
304 1.1 cgd (void)fprintf(stderr, "%s", *argv);
305 1.1 cgd for (p = argv + 1; *p; ++p)
306 1.1 cgd (void)fprintf(stderr, " %s", *p);
307 1.12 kleink if (pflag) {
308 1.12 kleink char buf[LINE_MAX + 1];
309 1.12 kleink
310 1.12 kleink (void)fprintf(stderr, "?...");
311 1.12 kleink fflush(stderr);
312 1.12 kleink if (fgets(buf, sizeof (buf), promptfile) == NULL) {
313 1.12 kleink rval = 1;
314 1.12 kleink return;
315 1.12 kleink }
316 1.12 kleink if (regexec(&yesexpr, buf, 0, NULL, 0) != 0)
317 1.12 kleink return;
318 1.12 kleink } else {
319 1.12 kleink (void)fprintf(stderr, "\n");
320 1.12 kleink }
321 1.1 cgd }
322 1.1 cgd noinvoke = 0;
323 1.1 cgd switch(pid = vfork()) {
324 1.1 cgd case -1:
325 1.7 jtc err(1, "vfork");
326 1.1 cgd case 0:
327 1.1 cgd execvp(argv[0], argv);
328 1.3 jtc noinvoke = (errno == ENOENT) ? 127 : 126;
329 1.7 jtc warn("%s", argv[0]);;
330 1.1 cgd _exit(1);
331 1.1 cgd }
332 1.1 cgd pid = waitpid(pid, &status, 0);
333 1.1 cgd if (pid == -1)
334 1.7 jtc err(1, "waitpid");
335 1.3 jtc
336 1.1 cgd /*
337 1.1 cgd * If we couldn't invoke the utility or the utility didn't exit
338 1.3 jtc * properly, quit with 127 or 126 respectively.
339 1.3 jtc */
340 1.3 jtc if (noinvoke)
341 1.3 jtc exit(noinvoke);
342 1.3 jtc
343 1.3 jtc /*
344 1.3 jtc * According to POSIX, we have to exit if the utility exits with
345 1.3 jtc * a 255 status, or is interrupted by a signal. xargs is allowed
346 1.3 jtc * to return any exit status between 1 and 125 in these cases, but
347 1.3 jtc * we'll use 124 and 125, the same values used by GNU xargs.
348 1.1 cgd */
349 1.3 jtc if (WIFEXITED(status)) {
350 1.3 jtc if (WEXITSTATUS (status) == 255) {
351 1.7 jtc warnx ("%s exited with status 255", argv[0]);
352 1.3 jtc exit(124);
353 1.3 jtc } else if (WEXITSTATUS (status) != 0) {
354 1.7 jtc rval = 123;
355 1.3 jtc }
356 1.3 jtc } else if (WIFSIGNALED (status)) {
357 1.11 christos if (WTERMSIG(status) < NSIG) {
358 1.10 fair warnx("%s terminated by SIG%s", argv[0],
359 1.10 fair sys_signame[WTERMSIG(status)]);
360 1.10 fair } else {
361 1.10 fair warnx("%s terminated by signal %d", argv[0],
362 1.10 fair WTERMSIG(status));
363 1.10 fair }
364 1.3 jtc exit(125);
365 1.3 jtc }
366 1.1 cgd }
367 1.1 cgd
368 1.12 kleink static void
369 1.1 cgd usage()
370 1.1 cgd {
371 1.1 cgd (void)fprintf(stderr,
372 1.12 kleink "usage: xargs [-0pt] [-n number [-x]] [-s size] [utility [argument ...]]\n");
373 1.1 cgd exit(1);
374 1.1 cgd }
375