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