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