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