xargs.c revision 1.10 1 1.10 fair /* $NetBSD: xargs.c,v 1.10 1998/04/14 09:26:33 fair 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.10 fair __RCSID("$NetBSD: xargs.c,v 1.10 1998/04/14 09:26:33 fair 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.1 cgd #include <errno.h>
55 1.1 cgd #include <stdio.h>
56 1.1 cgd #include <stdlib.h>
57 1.1 cgd #include <string.h>
58 1.1 cgd #include <unistd.h>
59 1.1 cgd #include <limits.h>
60 1.6 jtc #include <locale.h>
61 1.10 fair #include <signal.h>
62 1.7 jtc #include <err.h>
63 1.1 cgd #include "pathnames.h"
64 1.1 cgd
65 1.8 lukem int tflag, zflag, rval;
66 1.7 jtc
67 1.9 lukem void run __P((char **));
68 1.9 lukem int main __P((int, char **));
69 1.9 lukem void usage __P((void));
70 1.1 cgd
71 1.5 jtc int
72 1.1 cgd main(argc, argv)
73 1.1 cgd int argc;
74 1.1 cgd char **argv;
75 1.1 cgd {
76 1.9 lukem int ch;
77 1.9 lukem char *p, *bbp, *ebp, **bxp, **exp, **xp;
78 1.1 cgd int cnt, indouble, insingle, nargs, nflag, nline, xflag;
79 1.1 cgd char **av, *argp;
80 1.6 jtc
81 1.6 jtc setlocale(LC_ALL, "");
82 1.1 cgd
83 1.1 cgd /*
84 1.1 cgd * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
85 1.1 cgd * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given
86 1.1 cgd * that the smallest argument is 2 bytes in length, this means that
87 1.1 cgd * the number of arguments is limited to:
88 1.1 cgd *
89 1.1 cgd * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
90 1.1 cgd *
91 1.1 cgd * We arbitrarily limit the number of arguments to 5000. This is
92 1.1 cgd * allowed by POSIX.2 as long as the resulting minimum exec line is
93 1.1 cgd * at least LINE_MAX. Realloc'ing as necessary is possible, but
94 1.1 cgd * probably not worthwhile.
95 1.1 cgd */
96 1.1 cgd nargs = 5000;
97 1.1 cgd nline = ARG_MAX - 4 * 1024;
98 1.1 cgd nflag = xflag = 0;
99 1.8 lukem while ((ch = getopt(argc, argv, "0n:s:tx")) != -1)
100 1.1 cgd switch(ch) {
101 1.8 lukem case '0':
102 1.8 lukem zflag = 1;
103 1.8 lukem break;
104 1.1 cgd case 'n':
105 1.1 cgd nflag = 1;
106 1.1 cgd if ((nargs = atoi(optarg)) <= 0)
107 1.7 jtc errx(1, "illegal argument count");
108 1.1 cgd break;
109 1.1 cgd case 's':
110 1.1 cgd nline = atoi(optarg);
111 1.1 cgd break;
112 1.1 cgd case 't':
113 1.1 cgd tflag = 1;
114 1.1 cgd break;
115 1.1 cgd case 'x':
116 1.1 cgd xflag = 1;
117 1.1 cgd break;
118 1.1 cgd case '?':
119 1.1 cgd default:
120 1.1 cgd usage();
121 1.1 cgd }
122 1.1 cgd argc -= optind;
123 1.1 cgd argv += optind;
124 1.1 cgd
125 1.1 cgd if (xflag && !nflag)
126 1.1 cgd usage();
127 1.1 cgd
128 1.1 cgd /*
129 1.1 cgd * Allocate pointers for the utility name, the utility arguments,
130 1.1 cgd * the maximum arguments to be read from stdin and the trailing
131 1.1 cgd * NULL.
132 1.1 cgd */
133 1.1 cgd if (!(av = bxp =
134 1.1 cgd malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **))))
135 1.9 lukem err(1, "malloc");
136 1.1 cgd
137 1.1 cgd /*
138 1.1 cgd * Use the user's name for the utility as argv[0], just like the
139 1.1 cgd * shell. Echo is the default. Set up pointers for the user's
140 1.1 cgd * arguments.
141 1.1 cgd */
142 1.1 cgd if (!*argv)
143 1.1 cgd cnt = strlen(*bxp++ = _PATH_ECHO);
144 1.1 cgd else {
145 1.1 cgd cnt = 0;
146 1.1 cgd do {
147 1.1 cgd cnt += strlen(*bxp++ = *argv) + 1;
148 1.1 cgd } while (*++argv);
149 1.1 cgd }
150 1.1 cgd
151 1.1 cgd /*
152 1.1 cgd * Set up begin/end/traversing pointers into the array. The -n
153 1.1 cgd * count doesn't include the trailing NULL pointer, so the malloc
154 1.1 cgd * added in an extra slot.
155 1.1 cgd */
156 1.1 cgd exp = (xp = bxp) + nargs;
157 1.1 cgd
158 1.1 cgd /*
159 1.1 cgd * Allocate buffer space for the arguments read from stdin and the
160 1.1 cgd * trailing NULL. Buffer space is defined as the default or specified
161 1.1 cgd * space, minus the length of the utility name and arguments. Set up
162 1.1 cgd * begin/end/traversing pointers into the array. The -s count does
163 1.1 cgd * include the trailing NULL, so the malloc didn't add in an extra
164 1.1 cgd * slot.
165 1.1 cgd */
166 1.1 cgd nline -= cnt;
167 1.1 cgd if (nline <= 0)
168 1.7 jtc errx(1, "insufficient space for command");
169 1.1 cgd
170 1.1 cgd if (!(bbp = malloc((u_int)nline + 1)))
171 1.9 lukem err(1, "malloc");
172 1.1 cgd ebp = (argp = p = bbp) + nline - 1;
173 1.1 cgd
174 1.1 cgd for (insingle = indouble = 0;;)
175 1.1 cgd switch(ch = getchar()) {
176 1.1 cgd case EOF:
177 1.1 cgd /* No arguments since last exec. */
178 1.1 cgd if (p == bbp)
179 1.7 jtc exit(rval);
180 1.1 cgd
181 1.1 cgd /* Nothing since end of last argument. */
182 1.1 cgd if (argp == p) {
183 1.1 cgd *xp = NULL;
184 1.1 cgd run(av);
185 1.7 jtc exit(rval);
186 1.1 cgd }
187 1.1 cgd goto arg1;
188 1.1 cgd case ' ':
189 1.1 cgd case '\t':
190 1.1 cgd /* Quotes escape tabs and spaces. */
191 1.8 lukem if (insingle || indouble || zflag)
192 1.1 cgd goto addch;
193 1.1 cgd goto arg2;
194 1.8 lukem case '\0':
195 1.8 lukem if (zflag)
196 1.8 lukem goto arg2;
197 1.8 lukem goto addch;
198 1.1 cgd case '\n':
199 1.8 lukem if (zflag)
200 1.8 lukem goto addch;
201 1.1 cgd /* Empty lines are skipped. */
202 1.1 cgd if (argp == p)
203 1.1 cgd continue;
204 1.1 cgd
205 1.1 cgd /* Quotes do not escape newlines. */
206 1.1 cgd arg1: if (insingle || indouble)
207 1.7 jtc errx(1, "unterminated quote");
208 1.1 cgd
209 1.1 cgd arg2: *p = '\0';
210 1.1 cgd *xp++ = argp;
211 1.1 cgd
212 1.1 cgd /*
213 1.1 cgd * If max'd out on args or buffer, or reached EOF,
214 1.1 cgd * run the command. If xflag and max'd out on buffer
215 1.1 cgd * but not on args, object.
216 1.1 cgd */
217 1.1 cgd if (xp == exp || p == ebp || ch == EOF) {
218 1.1 cgd if (xflag && xp != exp && p == ebp)
219 1.7 jtc errx(1, "insufficient space for arguments");
220 1.1 cgd *xp = NULL;
221 1.1 cgd run(av);
222 1.1 cgd if (ch == EOF)
223 1.7 jtc exit(rval);
224 1.1 cgd p = bbp;
225 1.1 cgd xp = bxp;
226 1.1 cgd } else
227 1.1 cgd ++p;
228 1.1 cgd argp = p;
229 1.1 cgd break;
230 1.1 cgd case '\'':
231 1.8 lukem if (indouble || zflag)
232 1.1 cgd goto addch;
233 1.1 cgd insingle = !insingle;
234 1.1 cgd break;
235 1.1 cgd case '"':
236 1.8 lukem if (insingle || zflag)
237 1.1 cgd goto addch;
238 1.1 cgd indouble = !indouble;
239 1.1 cgd break;
240 1.1 cgd case '\\':
241 1.8 lukem if (zflag)
242 1.8 lukem goto addch;
243 1.1 cgd /* Backslash escapes anything, is escaped by quotes. */
244 1.1 cgd if (!insingle && !indouble && (ch = getchar()) == EOF)
245 1.7 jtc errx(1, "backslash at EOF");
246 1.1 cgd /* FALLTHROUGH */
247 1.1 cgd default:
248 1.1 cgd addch: if (p < ebp) {
249 1.1 cgd *p++ = ch;
250 1.1 cgd break;
251 1.1 cgd }
252 1.1 cgd
253 1.1 cgd /* If only one argument, not enough buffer space. */
254 1.1 cgd if (bxp == xp)
255 1.7 jtc errx(1, "insufficient space for argument");
256 1.1 cgd /* Didn't hit argument limit, so if xflag object. */
257 1.1 cgd if (xflag)
258 1.7 jtc errx(1, "insufficient space for arguments");
259 1.1 cgd
260 1.1 cgd *xp = NULL;
261 1.1 cgd run(av);
262 1.1 cgd xp = bxp;
263 1.1 cgd cnt = ebp - argp;
264 1.9 lukem memmove(bbp, argp, cnt);
265 1.1 cgd p = (argp = bbp) + cnt;
266 1.1 cgd *p++ = ch;
267 1.1 cgd break;
268 1.1 cgd }
269 1.1 cgd /* NOTREACHED */
270 1.1 cgd }
271 1.1 cgd
272 1.1 cgd void
273 1.1 cgd run(argv)
274 1.1 cgd char **argv;
275 1.1 cgd {
276 1.7 jtc volatile int noinvoke;
277 1.9 lukem char **p;
278 1.1 cgd pid_t pid;
279 1.1 cgd int status;
280 1.1 cgd
281 1.1 cgd if (tflag) {
282 1.1 cgd (void)fprintf(stderr, "%s", *argv);
283 1.1 cgd for (p = argv + 1; *p; ++p)
284 1.1 cgd (void)fprintf(stderr, " %s", *p);
285 1.1 cgd (void)fprintf(stderr, "\n");
286 1.1 cgd (void)fflush(stderr);
287 1.1 cgd }
288 1.1 cgd noinvoke = 0;
289 1.1 cgd switch(pid = vfork()) {
290 1.1 cgd case -1:
291 1.7 jtc err(1, "vfork");
292 1.1 cgd case 0:
293 1.1 cgd execvp(argv[0], argv);
294 1.3 jtc noinvoke = (errno == ENOENT) ? 127 : 126;
295 1.7 jtc warn("%s", argv[0]);;
296 1.1 cgd _exit(1);
297 1.1 cgd }
298 1.1 cgd pid = waitpid(pid, &status, 0);
299 1.1 cgd if (pid == -1)
300 1.7 jtc err(1, "waitpid");
301 1.3 jtc
302 1.1 cgd /*
303 1.1 cgd * If we couldn't invoke the utility or the utility didn't exit
304 1.3 jtc * properly, quit with 127 or 126 respectively.
305 1.3 jtc */
306 1.3 jtc if (noinvoke)
307 1.3 jtc exit(noinvoke);
308 1.3 jtc
309 1.3 jtc /*
310 1.3 jtc * According to POSIX, we have to exit if the utility exits with
311 1.3 jtc * a 255 status, or is interrupted by a signal. xargs is allowed
312 1.3 jtc * to return any exit status between 1 and 125 in these cases, but
313 1.3 jtc * we'll use 124 and 125, the same values used by GNU xargs.
314 1.1 cgd */
315 1.3 jtc if (WIFEXITED(status)) {
316 1.3 jtc if (WEXITSTATUS (status) == 255) {
317 1.7 jtc warnx ("%s exited with status 255", argv[0]);
318 1.3 jtc exit(124);
319 1.3 jtc } else if (WEXITSTATUS (status) != 0) {
320 1.7 jtc rval = 123;
321 1.3 jtc }
322 1.3 jtc } else if (WIFSIGNALED (status)) {
323 1.10 fair if (WTERMSIG(status) < _NSIG) {
324 1.10 fair warnx("%s terminated by SIG%s", argv[0],
325 1.10 fair sys_signame[WTERMSIG(status)]);
326 1.10 fair } else {
327 1.10 fair warnx("%s terminated by signal %d", argv[0],
328 1.10 fair WTERMSIG(status));
329 1.10 fair }
330 1.3 jtc exit(125);
331 1.3 jtc }
332 1.1 cgd }
333 1.1 cgd
334 1.1 cgd void
335 1.1 cgd usage()
336 1.1 cgd {
337 1.1 cgd (void)fprintf(stderr,
338 1.8 lukem "usage: xargs [-0t] [-n number [-x]] [-s size] [utility [argument ...]]\n");
339 1.1 cgd exit(1);
340 1.1 cgd }
341