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} |