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 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $ 33 * 34 * @(#) Copyright (c) 1990, 1993 The Regents of the University of California. All rights reserved. 35 * @(#)xargs.c 8.1 (Berkeley) 6/6/93 36 * $FreeBSD: src/usr.bin/xargs/xargs.c,v 1.9.2.6 2003/06/01 21:40:35 mux Exp $ 37 */ 38 39 #include <sys/types.h> 40 #include <sys/wait.h> 41 42 #include <err.h> 43 #include <errno.h> 44 #include <fcntl.h> 45 #ifndef BOOTSTRAPPING 46 #include <langinfo.h> 47 #endif 48 #include <locale.h> 49 #include <paths.h> 50 #include <regex.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 56 #include "pathnames.h" 57 58 static void parse_input(int, char *[]); 59 static void prerun(int, char *[]); 60 static int prompt(void); 61 static void run(char **); 62 static void usage(void); 63 void strnsubst(char **, const char *, const char *, size_t); 64 static void waitchildren(const char *, int); 65 66 static char echo[] = _PATH_ECHO; 67 static char **av, **bxp, **ep, **expx, **xp; 68 static char *argp, *bbp, *ebp, *inpline, *p, *replstr; 69 static const char *eofstr; 70 static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag; 71 static int cnt, Iflag, jfound, Lflag, wasquoted, xflag; 72 static int curprocs, maxprocs; 73 static volatile int childerr; 74 75 extern char **environ; 76 77 int 78 main(int argc, char *argv[]) 79 { 80 char *tmp; 81 long arg_max; 82 int ch, Jflag, nargs, nflag, nline; 83 size_t linelen; 84 85 inpline = replstr = NULL; 86 ep = environ; 87 eofstr = ""; 88 Jflag = nflag = 0; 89 90 (void)setlocale(LC_MESSAGES, ""); 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. 99 * 100 * We arbitrarily limit the number of arguments to 5000. This is 101 * allowed by POSIX.2 as long as the resulting minimum exec line is 102 * at least LINE_MAX. Realloc'ing as necessary is possible, but 103 * probably not worthwhile. 104 */ 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 != NULL) { 110 /* 1 byte for each '\0' */ 111 nline -= strlen(*ep++) + 1 + sizeof(*ep); 112 } 113 114 maxprocs = 1; 115 while ((ch = getopt(argc, argv, "0E:I:J:L:n:opP:R:s:tx")) != -1) 116 switch(ch) { 117 case 'E': 118 eofstr = optarg; 119 break; 120 case 'I': 121 Jflag = 0; 122 Iflag = 1; 123 Lflag = 1; 124 replstr = optarg; 125 break; 126 case 'J': 127 Iflag = 0; 128 Jflag = 1; 129 replstr = optarg; 130 break; 131 case 'L': 132 Lflag = strtol(optarg, &tmp, 10); 133 if (*tmp != 0 || *optarg == 0) 134 errx(1, "illegal argument count"); 135 break; 136 case 'n': 137 nflag = 1; 138 if ((nargs = atoi(optarg)) <= 0) 139 errx(1, "illegal argument count"); 140 break; 141 case 'o': 142 oflag = 1; 143 break; 144 case 'p': 145 pflag = 1; 146 break; 147 case 'P': 148 if ((maxprocs = atoi(optarg)) <= 0) 149 errx(1, "max.processes must be >0"); 150 break; 151 case 'R': 152 if ((Rflag = atoi(optarg)) <= 0) 153 errx(1, "illegal number of replacements"); 154 break; 155 case 's': 156 nline = atoi(optarg); 157 break; 158 case 't': 159 tflag = 1; 160 break; 161 case 'x': 162 xflag = 1; 163 break; 164 case '0': 165 zflag = 1; 166 break; 167 case '?': 168 default: 169 usage(); 170 } 171 argc -= optind; 172 argv += optind; 173 174 if (!Iflag && Rflag) 175 usage(); 176 if (Iflag && !Rflag) 177 Rflag = 5; 178 if (xflag && !nflag) 179 usage(); 180 if (Iflag || Lflag) 181 xflag = 1; 182 if (replstr != NULL && *replstr == '\0') 183 errx(1, "replstr may not be empty"); 184 185 /* 186 * Allocate pointers for the utility name, the utility arguments, 187 * the maximum arguments to be read from stdin and the trailing 188 * NULL. 189 */ 190 linelen = 1 + argc + nargs + 1; 191 if ((av = bxp = malloc(linelen * sizeof(char **))) == NULL) 192 errx(1, "malloc failed"); 193 194 /* 195 * Use the user's name for the utility as argv[0], just like the 196 * shell. Echo is the default. Set up pointers for the user's 197 * arguments. 198 */ 199 if (*argv == NULL) 200 cnt = strlen(*bxp++ = echo); 201 else { 202 do { 203 if (Jflag && strcmp(*argv, replstr) == 0) { 204 char **avj; 205 jfound = 1; 206 argv++; 207 for (avj = argv; *avj; avj++) 208 cnt += strlen(*avj) + 1; 209 break; 210 } 211 cnt += strlen(*bxp++ = *argv) + 1; 212 } while (*++argv != NULL); 213 } 214 215 /* 216 * Set up begin/end/traversing pointers into the array. The -n 217 * count doesn't include the trailing NULL pointer, so the malloc 218 * added in an extra slot. 219 */ 220 expx = (xp = bxp) + nargs; 221 222 /* 223 * Allocate buffer space for the arguments read from stdin and the 224 * trailing NULL. Buffer space is defined as the default or specified 225 * space, minus the length of the utility name and arguments. Set up 226 * begin/end/traversing pointers into the array. The -s count does 227 * include the trailing NULL, so the malloc didn't add in an extra 228 * slot. 229 */ 230 nline -= cnt; 231 if (nline <= 0) 232 errx(1, "insufficient space for command"); 233 234 if ((bbp = malloc((size_t)(nline + 1))) == NULL) 235 errx(1, "malloc failed"); 236 ebp = (argp = p = bbp) + nline - 1; 237 for (;;) 238 parse_input(argc, argv); 239 } 240 241 static void 242 parse_input(int argc, char *argv[]) 243 { 244 int ch, foundeof; 245 char **avj; 246 247 foundeof = 0; 248 249 switch(ch = getchar()) { 250 case EOF: 251 /* No arguments since last exec. */ 252 if (p == bbp) { 253 waitchildren(*argv, 1); 254 exit(rval); 255 } 256 goto arg1; 257 case ' ': 258 case '\t': 259 /* Quotes escape tabs and spaces. */ 260 if (insingle || indouble || zflag) 261 goto addch; 262 goto arg2; 263 case '\0': 264 if (zflag) 265 goto arg2; 266 goto addch; 267 case '\n': 268 count++; 269 if (zflag) 270 goto addch; 271 272 /* Quotes do not escape newlines. */ 273 arg1: if (insingle || indouble) 274 errx(1, "unterminated quote"); 275 arg2: 276 foundeof = *eofstr != '\0' && 277 strcmp(argp, eofstr) == 0; 278 279 /* Do not make empty args unless they are quoted */ 280 if ((argp != p || wasquoted) && !foundeof) { 281 *p++ = '\0'; 282 *xp++ = argp; 283 if (Iflag) { 284 size_t curlen; 285 286 if (inpline == NULL) 287 curlen = 0; 288 else { 289 /* 290 * If this string is not zero 291 * length, append a space for 292 * separation before the next 293 * argument. 294 */ 295 if ((curlen = strlen(inpline))) 296 strcat(inpline, " "); 297 } 298 curlen++; 299 /* 300 * Allocate enough to hold what we will 301 * be holding in a second, and to append 302 * a space next time through, if we have 303 * to. 304 */ 305 inpline = realloc(inpline, curlen + 2 + 306 strlen(argp)); 307 if (inpline == NULL) 308 errx(1, "realloc failed"); 309 if (curlen == 1) 310 strcpy(inpline, argp); 311 else 312 strcat(inpline, argp); 313 } 314 } 315 316 /* 317 * If max'd out on args or buffer, or reached EOF, 318 * run the command. If xflag and max'd out on buffer 319 * but not on args, object. Having reached the limit 320 * of input lines, as specified by -L is the same as 321 * maxing out on arguments. 322 */ 323 if (xp == expx || p > ebp || ch == EOF || 324 (Lflag <= count && xflag) || foundeof) { 325 if (xflag && xp != expx && p > ebp) 326 errx(1, "insufficient space for arguments"); 327 if (jfound) { 328 for (avj = argv; *avj; avj++) 329 *xp++ = *avj; 330 } 331 prerun(argc, av); 332 if (ch == EOF || foundeof) { 333 waitchildren(*argv, 1); 334 exit(rval); 335 } 336 p = bbp; 337 xp = bxp; 338 count = 0; 339 } 340 argp = p; 341 wasquoted = 0; 342 break; 343 case '\'': 344 if (indouble || zflag) 345 goto addch; 346 insingle = !insingle; 347 wasquoted = 1; 348 break; 349 case '"': 350 if (insingle || zflag) 351 goto addch; 352 indouble = !indouble; 353 wasquoted = 1; 354 break; 355 case '\\': 356 if (zflag) 357 goto addch; 358 /* Backslash escapes anything, is escaped by quotes. */ 359 if (!insingle && !indouble && (ch = getchar()) == EOF) 360 errx(1, "backslash at EOF"); 361 /* FALLTHROUGH */ 362 default: 363 addch: if (p < ebp) { 364 *p++ = ch; 365 break; 366 } 367 368 /* If only one argument, not enough buffer space. */ 369 if (bxp == xp) 370 errx(1, "insufficient space for argument"); 371 /* Didn't hit argument limit, so if xflag object. */ 372 if (xflag) 373 errx(1, "insufficient space for arguments"); 374 375 if (jfound) { 376 for (avj = argv; *avj; avj++) 377 *xp++ = *avj; 378 } 379 prerun(argc, av); 380 xp = bxp; 381 cnt = ebp - argp; 382 memcpy(bbp, argp, (size_t)cnt); 383 p = (argp = bbp) + cnt; 384 *p++ = ch; 385 break; 386 } 387 return; 388 } 389 390 /* 391 * Do things necessary before run()'ing, such as -I substitution, 392 * and then call run(). 393 */ 394 static void 395 prerun(int argc, char *argv[]) 396 { 397 char **tmp, **tmp2, **avj; 398 int repls; 399 400 repls = Rflag; 401 402 if (argc == 0 || repls == 0) { 403 *xp = NULL; 404 run(argv); 405 return; 406 } 407 408 avj = argv; 409 410 /* 411 * Allocate memory to hold the argument list, and 412 * a NULL at the tail. 413 */ 414 tmp = malloc((argc + 1) * sizeof(char**)); 415 if (tmp == NULL) 416 errx(1, "malloc failed"); 417 tmp2 = tmp; 418 419 /* 420 * Save the first argument and iterate over it, we 421 * cannot do strnsubst() to it. 422 */ 423 if ((*tmp++ = strdup(*avj++)) == NULL) 424 errx(1, "strdup failed"); 425 426 /* 427 * For each argument to utility, if we have not used up 428 * the number of replacements we are allowed to do, and 429 * if the argument contains at least one occurrence of 430 * replstr, call strnsubst(), else just save the string. 431 * Iterations over elements of avj and tmp are done 432 * where appropriate. 433 */ 434 while (--argc) { 435 *tmp = *avj++; 436 if (repls && strstr(*tmp, replstr) != NULL) { 437 strnsubst(tmp++, replstr, inpline, (size_t)255); 438 repls--; 439 } else { 440 if ((*tmp = strdup(*tmp)) == NULL) 441 errx(1, "strdup failed"); 442 tmp++; 443 } 444 } 445 446 /* 447 * Run it. 448 */ 449 *tmp = NULL; 450 run(tmp2); 451 452 /* 453 * Walk from the tail to the head, free along the way. 454 */ 455 for (; tmp2 != tmp; tmp--) 456 free(*tmp); 457 /* 458 * Now free the list itself. 459 */ 460 free(tmp2); 461 462 /* 463 * Free the input line buffer, if we have one. 464 */ 465 if (inpline != NULL) { 466 free(inpline); 467 inpline = NULL; 468 } 469 } 470 471 static void 472 run(char **argv) 473 { 474 char **avec; 475 pid_t pid; 476 477 /* 478 * If the user wants to be notified of each command before it is 479 * executed, notify them. If they want the notification to be 480 * followed by a prompt, then prompt them. 481 */ 482 if (tflag || pflag) { 483 (void)fprintf(stderr, "%s", *argv); 484 for (avec = argv + 1; *avec != NULL; ++avec) 485 (void)fprintf(stderr, " %s", *avec); 486 /* 487 * If the user has asked to be prompted, do so. 488 */ 489 if (pflag) 490 /* 491 * If they asked not to exec, return without execution 492 * but if they asked to, go to the execution. If we 493 * could not open their tty, break the switch and drop 494 * back to -t behaviour. 495 */ 496 switch (prompt()) { 497 case 0: 498 return; 499 case 1: 500 goto exec; 501 case 2: 502 break; 503 } 504 (void)fprintf(stderr, "\n"); 505 (void)fflush(stderr); 506 } 507 exec: 508 childerr = 0; 509 switch(pid = vfork()) { 510 case -1: 511 err(1, "vfork"); 512 case 0: 513 close(0); 514 if (oflag) { 515 if (open("/dev/tty", O_RDONLY) == -1) 516 err(1, "open /dev/tty"); 517 } else { 518 if (open("/dev/null", O_RDONLY) == -1) 519 err(1, "open /dev/null"); 520 } 521 execvp(argv[0], argv); 522 childerr = errno; 523 _exit(1); 524 } 525 curprocs++; 526 waitchildren(*argv, 0); 527 } 528 529 /* 530 * Handle child processes. 531 */ 532 static void 533 waitchildren(const char *name, int waitall) 534 { 535 pid_t pid; 536 int status; 537 538 while ((pid = wait3(&status, !waitall && curprocs < maxprocs ? 539 WNOHANG : 0, NULL)) > 0) { 540 curprocs--; 541 542 /* If we couldn't invoke the utility, exit. */ 543 if (childerr != 0) { 544 errno = childerr; 545 err(errno == ENOENT ? 127 : 126, "%s", name); 546 } 547 548 /* 549 * If utility signaled or exited with a value of 255, 550 * exit 1-125. 551 */ 552 if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255) 553 exit(1); 554 if (WEXITSTATUS(status)) 555 rval = 1; 556 } 557 if (pid == -1 && errno != ECHILD) 558 err(1, "wait3"); 559 } 560 561 /* 562 * Prompt the user about running a command. 563 */ 564 static int 565 prompt(void) 566 { 567 regex_t cre; 568 size_t rsize; 569 int match; 570 char *response; 571 FILE *ttyfp; 572 573 if ((ttyfp = fopen(_PATH_TTY, "r")) == NULL) 574 return (2); /* Indicate that the TTY failed to open. */ 575 (void)fprintf(stderr, "?..."); 576 (void)fflush(stderr); 577 if ((response = fgetln(ttyfp, &rsize)) == NULL || 578 regcomp(&cre, 579 #ifdef BOOTSTRAPPING 580 "^[yY]", 581 #else 582 nl_langinfo(YESEXPR), 583 #endif 584 REG_BASIC) != 0) { 585 (void)fclose(ttyfp); 586 return (0); 587 } 588 match = regexec(&cre, response, 0, NULL, 0); 589 (void)fclose(ttyfp); 590 regfree(&cre); 591 return (match == 0); 592 } 593 594 static void 595 usage(void) 596 { 597 fprintf(stderr, 598 "usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n" 599 " [-L number] [-n number [-x] [-P maxprocs] [-s size]\n" 600 " [utility [argument ...]]\n"); 601 exit(1); 602 } 603