Deleted Added
full compact
xargs.c (92377) xargs.c (95080)
1/*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * John B. Roll Jr.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 18 unchanged lines hidden (view full) ---

27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
1/*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * John B. Roll Jr.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 18 unchanged lines hidden (view full) ---

27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $
35 */
36
37#ifndef lint
38static const char copyright[] =
39"@(#) Copyright (c) 1990, 1993\n\
40 The Regents of the University of California. All rights reserved.\n";
41#endif /* not lint */
42
43#if 0
44#ifndef lint
45static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93";
46#endif /* not lint */
47#endif
48
49#include <sys/cdefs.h>
37 */
38
39#ifndef lint
40static const char copyright[] =
41"@(#) Copyright (c) 1990, 1993\n\
42 The Regents of the University of California. All rights reserved.\n";
43#endif /* not lint */
44
45#if 0
46#ifndef lint
47static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93";
48#endif /* not lint */
49#endif
50
51#include <sys/cdefs.h>
50__FBSDID("$FreeBSD: head/usr.bin/xargs/xargs.c 92377 2002-03-15 22:54:58Z jmallett $");
52__FBSDID("$FreeBSD: head/usr.bin/xargs/xargs.c 95080 2002-04-19 23:28:54Z jmallett $");
51
52#include <sys/types.h>
53#include <sys/wait.h>
54
55#include <err.h>
56#include <errno.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <unistd.h>
61
62#include "pathnames.h"
63
53
54#include <sys/types.h>
55#include <sys/wait.h>
56
57#include <err.h>
58#include <errno.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <unistd.h>
63
64#include "pathnames.h"
65
64int tflag, rval;
65int zflag;
66
67void run(char **);
66static void run(char **);
68static void usage(void);
67static void usage(void);
68void strnsubst(char **, const char *, const char *, size_t);
69
70static char echo[] = _PATH_ECHO;
69
70static char echo[] = _PATH_ECHO;
71static int pflag, tflag, rval, zflag;
71
72extern char *environ[];
73
74int
75main(int argc, char **argv)
76{
72
73extern char *environ[];
74
75int
76main(int argc, char **argv)
77{
77 int ch;
78 char *p, *bbp, **bxp, *ebp, **exp, **xp;
79 int cnt, jfound, indouble, insingle;
80 int nargs, nflag, nline, xflag, wasquoted;
81 char **av, **avj, *argp, **ep, *replstr;
82 long arg_max;
78 long arg_max;
79 int argumentc, ch, cnt, count, Iflag, indouble, insingle, jfound, lflag;
80 int nargs, nflag, nline, wasquoted, foundeof, xflag;
81 size_t linelen;
82 const char *eofstr;
83 char **av, **avj, **bxp, **ep, **exp, **xp;
84 char *argp, *bbp, *ebp, *inpline, *p, *replstr;
83
84 ep = environ;
85
86 ep = environ;
85 jfound = 0;
86 replstr = NULL; /* set if user requests -J */
87 inpline = replstr = NULL;
88 eofstr = "";
89 argumentc = cnt = count = Iflag = jfound = lflag = nflag = xflag =
90 wasquoted = 0;
87
88 /*
89 * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
90 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given
91 * that the smallest argument is 2 bytes in length, this means that
92 * the number of arguments is limited to:
93 *
94 * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.

--- 6 unchanged lines hidden (view full) ---

101 nargs = 5000;
102 if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
103 errx(1, "sysconf(_SC_ARG_MAX) failed");
104 nline = arg_max - 4 * 1024;
105 while (*ep) {
106 /* 1 byte for each '\0' */
107 nline -= strlen(*ep++) + 1 + sizeof(*ep);
108 }
91
92 /*
93 * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
94 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given
95 * that the smallest argument is 2 bytes in length, this means that
96 * the number of arguments is limited to:
97 *
98 * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.

--- 6 unchanged lines hidden (view full) ---

105 nargs = 5000;
106 if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
107 errx(1, "sysconf(_SC_ARG_MAX) failed");
108 nline = arg_max - 4 * 1024;
109 while (*ep) {
110 /* 1 byte for each '\0' */
111 nline -= strlen(*ep++) + 1 + sizeof(*ep);
112 }
109 nflag = xflag = wasquoted = 0;
110 while ((ch = getopt(argc, argv, "0J:n:s:tx")) != -1)
113 while ((ch = getopt(argc, argv, "0E:I:J:L:n:ps:tx")) != -1)
111 switch(ch) {
114 switch(ch) {
115 case 'E':
116 eofstr = optarg;
117 break;
118 case 'I':
119 Iflag = 1;
120 lflag = 1;
121 replstr = optarg;
122 break;
112 case 'J':
113 replstr = optarg;
114 break;
123 case 'J':
124 replstr = optarg;
125 break;
126 case 'L':
127 lflag = atoi(optarg);
128 break;
115 case 'n':
116 nflag = 1;
117 if ((nargs = atoi(optarg)) <= 0)
118 errx(1, "illegal argument count");
119 break;
129 case 'n':
130 nflag = 1;
131 if ((nargs = atoi(optarg)) <= 0)
132 errx(1, "illegal argument count");
133 break;
134 case 'p':
135 pflag = 1;
136 break;
120 case 's':
121 nline = atoi(optarg);
122 break;
123 case 't':
124 tflag = 1;
125 break;
126 case 'x':
127 xflag = 1;

--- 5 unchanged lines hidden (view full) ---

133 default:
134 usage();
135 }
136 argc -= optind;
137 argv += optind;
138
139 if (xflag && !nflag)
140 usage();
137 case 's':
138 nline = atoi(optarg);
139 break;
140 case 't':
141 tflag = 1;
142 break;
143 case 'x':
144 xflag = 1;

--- 5 unchanged lines hidden (view full) ---

150 default:
151 usage();
152 }
153 argc -= optind;
154 argv += optind;
155
156 if (xflag && !nflag)
157 usage();
158 if (Iflag || lflag)
159 xflag = 1;
160 if (replstr != NULL && *replstr == '\0')
161 errx(1, "replstr may not be empty");
141
142 /*
143 * Allocate pointers for the utility name, the utility arguments,
144 * the maximum arguments to be read from stdin and the trailing
145 * NULL.
146 */
162
163 /*
164 * Allocate pointers for the utility name, the utility arguments,
165 * the maximum arguments to be read from stdin and the trailing
166 * NULL.
167 */
147 if (!(av = bxp =
148 malloc((u_int)(1 + argc + nargs + 1) * sizeof(char **))))
149 errx(1, "malloc");
168 linelen = 1 + argc + nargs + 1;
169 if ((av = bxp = calloc(linelen * sizeof(char **), 1)) == NULL)
170 err(1, "calloc");
150
151 /*
152 * Use the user's name for the utility as argv[0], just like the
153 * shell. Echo is the default. Set up pointers for the user's
154 * arguments.
155 */
156 if (!*argv)
157 cnt = strlen((*bxp++ = echo));
158 else {
171
172 /*
173 * Use the user's name for the utility as argv[0], just like the
174 * shell. Echo is the default. Set up pointers for the user's
175 * arguments.
176 */
177 if (!*argv)
178 cnt = strlen((*bxp++ = echo));
179 else {
159 cnt = 0;
160 do {
180 do {
161 if (replstr && strcmp(*argv, replstr) == 0) {
181 if (!Iflag && replstr && strcmp(*argv, replstr) == 0) {
162 jfound = 1;
163 argv++;
164 for (avj = argv; *avj; avj++)
165 cnt += strlen(*avj) + 1;
166 break;
167 }
168 cnt += strlen(*bxp++ = *argv) + 1;
169 } while (*++argv);

--- 13 unchanged lines hidden (view full) ---

183 * begin/end/traversing pointers into the array. The -s count does
184 * include the trailing NULL, so the malloc didn't add in an extra
185 * slot.
186 */
187 nline -= cnt;
188 if (nline <= 0)
189 errx(1, "insufficient space for command");
190
182 jfound = 1;
183 argv++;
184 for (avj = argv; *avj; avj++)
185 cnt += strlen(*avj) + 1;
186 break;
187 }
188 cnt += strlen(*bxp++ = *argv) + 1;
189 } while (*++argv);

--- 13 unchanged lines hidden (view full) ---

203 * begin/end/traversing pointers into the array. The -s count does
204 * include the trailing NULL, so the malloc didn't add in an extra
205 * slot.
206 */
207 nline -= cnt;
208 if (nline <= 0)
209 errx(1, "insufficient space for command");
210
191 if (!(bbp = malloc((u_int)nline + 1)))
192 errx(1, "malloc");
211 if ((bbp = malloc((u_int)nline + 1)) == NULL)
212 err(1, "malloc");
193 ebp = (argp = p = bbp) + nline - 1;
194
195 for (insingle = indouble = 0;;)
196 switch(ch = getchar()) {
197 case EOF:
198 /* No arguments since last exec. */
199 if (p == bbp)
200 exit(rval);

--- 4 unchanged lines hidden (view full) ---

205 if (insingle || indouble || zflag)
206 goto addch;
207 goto arg2;
208 case '\0':
209 if (zflag)
210 goto arg2;
211 goto addch;
212 case '\n':
213 ebp = (argp = p = bbp) + nline - 1;
214
215 for (insingle = indouble = 0;;)
216 switch(ch = getchar()) {
217 case EOF:
218 /* No arguments since last exec. */
219 if (p == bbp)
220 exit(rval);

--- 4 unchanged lines hidden (view full) ---

225 if (insingle || indouble || zflag)
226 goto addch;
227 goto arg2;
228 case '\0':
229 if (zflag)
230 goto arg2;
231 goto addch;
232 case '\n':
233 count++;
213 if (zflag)
214 goto addch;
215
216 /* Quotes do not escape newlines. */
217arg1: if (insingle || indouble)
218 errx(1, "unterminated quote");
219
220arg2:
234 if (zflag)
235 goto addch;
236
237 /* Quotes do not escape newlines. */
238arg1: if (insingle || indouble)
239 errx(1, "unterminated quote");
240
241arg2:
242 foundeof = *eofstr != '\0' &&
243 strcmp(argp, eofstr) == 0;
244
221 /* Do not make empty args unless they are quoted */
245 /* Do not make empty args unless they are quoted */
222 if (argp != p || wasquoted) {
246 if ((argp != p || wasquoted) && !foundeof) {
223 *p++ = '\0';
224 *xp++ = argp;
247 *p++ = '\0';
248 *xp++ = argp;
249 if (Iflag) {
250 char *realloc_holder;
251 size_t curlen;
252 realloc_holder = inpline;
253 if (realloc_holder == NULL)
254 curlen = 0;
255 else {
256 curlen = strlen(realloc_holder);
257 if (curlen)
258 strcat(inpline, " ");
259 }
260 curlen++;
261 argumentc++;
262 inpline = realloc(realloc_holder, strlen(argp) +
263 curlen);
264 if (inpline == NULL)
265 err(1, "realloc");
266 if (curlen == 1)
267 strcpy(inpline, argp);
268 else
269 strcat(inpline, argp);
270 }
225 }
226
227 /*
228 * If max'd out on args or buffer, or reached EOF,
229 * run the command. If xflag and max'd out on buffer
230 * but not on args, object.
231 */
271 }
272
273 /*
274 * If max'd out on args or buffer, or reached EOF,
275 * run the command. If xflag and max'd out on buffer
276 * but not on args, object.
277 */
232 if (xp == exp || p > ebp || ch == EOF) {
278 if (xp == exp || p > ebp || ch == EOF || (lflag <= count && xflag) || foundeof) {
233 if (xflag && xp != exp && p > ebp)
234 errx(1, "insufficient space for arguments");
235 if (jfound) {
236 for (avj = argv; *avj; avj++)
237 *xp++ = *avj;
238 }
279 if (xflag && xp != exp && p > ebp)
280 errx(1, "insufficient space for arguments");
281 if (jfound) {
282 for (avj = argv; *avj; avj++)
283 *xp++ = *avj;
284 }
239 *xp = NULL;
240 run(av);
241 if (ch == EOF)
285 if (Iflag) {
286 char **tmp, **tmp2;
287 size_t repls;
288
289 tmp = calloc(linelen * sizeof(char **), 1);
290 if (tmp == NULL)
291 err(1, "malloc");
292 tmp2 = tmp;
293 for (repls = 5, avj = av; *avj != NULL; avj++) {
294 *tmp = *avj;
295 if (avj != av && repls > 0 &&
296 strstr(*tmp, replstr) != NULL) {
297 strnsubst(tmp, replstr,
298 inpline, 255);
299 repls--;
300 } else {
301 *tmp = strdup(*avj);
302 if (*tmp == NULL)
303 err(1,
304 "strdup");
305 }
306 tmp++;
307 }
308 do {
309 if (*tmp != NULL)
310 free(*tmp);
311 tmp--;
312 } while (--argumentc);
313 *tmp = *xp = NULL;
314 run(tmp2);
315 for (; tmp2 != tmp; tmp--)
316 free(*tmp);
317 free(tmp2);
318 free(inpline);
319 inpline = strdup("");
320 argumentc = 0;
321 } else {
322 *xp = NULL;
323 run(av);
324 }
325 if (ch == EOF || foundeof)
242 exit(rval);
243 p = bbp;
244 xp = bxp;
326 exit(rval);
327 p = bbp;
328 xp = bxp;
329 count = 0;
245 }
246 argp = p;
247 wasquoted = 0;
248 break;
249 case '\'':
250 if (indouble || zflag)
251 goto addch;
252 insingle = !insingle;

--- 28 unchanged lines hidden (view full) ---

281 if (jfound) {
282 for (avj = argv; *avj; avj++)
283 *xp++ = *avj;
284 }
285 *xp = NULL;
286 run(av);
287 xp = bxp;
288 cnt = ebp - argp;
330 }
331 argp = p;
332 wasquoted = 0;
333 break;
334 case '\'':
335 if (indouble || zflag)
336 goto addch;
337 insingle = !insingle;

--- 28 unchanged lines hidden (view full) ---

366 if (jfound) {
367 for (avj = argv; *avj; avj++)
368 *xp++ = *avj;
369 }
370 *xp = NULL;
371 run(av);
372 xp = bxp;
373 cnt = ebp - argp;
289 bcopy(argp, bbp, cnt);
374 memcpy(bbp, argp, (size_t)cnt);
290 p = (argp = bbp) + cnt;
291 *p++ = ch;
292 break;
293 }
294 /* NOTREACHED */
295}
296
375 p = (argp = bbp) + cnt;
376 *p++ = ch;
377 break;
378 }
379 /* NOTREACHED */
380}
381
297void
382static void
298run(char **argv)
299{
300 volatile int childerr;
301 char **p;
383run(char **argv)
384{
385 volatile int childerr;
386 char **p;
387 FILE *ttyfp;
302 pid_t pid;
388 pid_t pid;
303 int status;
389 int ch, status;
304
390
305 if (tflag) {
391 if (tflag || pflag) {
306 (void)fprintf(stderr, "%s", *argv);
307 for (p = argv + 1; *p; ++p)
308 (void)fprintf(stderr, " %s", *p);
392 (void)fprintf(stderr, "%s", *argv);
393 for (p = argv + 1; *p; ++p)
394 (void)fprintf(stderr, " %s", *p);
309 (void)fprintf(stderr, "\n");
310 (void)fflush(stderr);
395 if (pflag) {
396 if ((ttyfp = fopen("/dev/tty", "r")) != NULL) {
397 (void)fprintf(stderr, "?");
398 (void)fflush(stderr);
399 ch = getc(ttyfp);
400 fclose(ttyfp);
401 if (ch != 'y')
402 return;
403 }
404 } else {
405 (void)fprintf(stderr, "\n");
406 (void)fflush(stderr);
407 }
311 }
312 childerr = 0;
313 switch(pid = vfork()) {
314 case -1:
315 err(1, "vfork");
316 case 0:
317 execvp(argv[0], argv);
318 childerr = errno;
319 _exit(1);
320 }
321 pid = waitpid(pid, &status, 0);
322 if (pid == -1)
323 err(1, "waitpid");
408 }
409 childerr = 0;
410 switch(pid = vfork()) {
411 case -1:
412 err(1, "vfork");
413 case 0:
414 execvp(argv[0], argv);
415 childerr = errno;
416 _exit(1);
417 }
418 pid = waitpid(pid, &status, 0);
419 if (pid == -1)
420 err(1, "waitpid");
324 /* If we couldn't invoke the utility, exit 127. */
325 if (childerr != 0) {
326 errno = childerr;
327 warn("%s", argv[0]);
328 exit(127);
329 }
421 /* If we couldn't invoke the utility, exit. */
422 if (childerr != 0)
423 err(childerr == ENOENT ? 127 : 126, "%s", *argv);
330 /* If utility signaled or exited with a value of 255, exit 1-125. */
331 if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255)
332 exit(1);
333 if (WEXITSTATUS(status))
334 rval = 1;
335}
336
337static void
338usage(void)
339{
340 fprintf(stderr,
424 /* If utility signaled or exited with a value of 255, exit 1-125. */
425 if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255)
426 exit(1);
427 if (WEXITSTATUS(status))
428 rval = 1;
429}
430
431static void
432usage(void)
433{
434 fprintf(stderr,
341 "usage: xargs [-0t] [-J replstr] [-n number [-x]] [-s size]\n"
342 " [utility [argument ...]]\n");
435"usage: xargs [-0pt] [-E eofstr] [-I replstr] [-J replstr] [-L number]\n");
436 fprintf(stderr,
437" [-n number [-x] [-s size] [utility [argument ...]]\n");
343 exit(1);
344}
438 exit(1);
439}