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